· Zen HuiFer · Learn · 4 min read
A New JavaScript Proposal to Say Goodbye to Try Catch!
Discover the new JavaScript proposal for a safer assignment operator that aims to streamline error handling. Say goodbye to try-catch with ?=, enhancing code security and simplicity.
Error handling has always been an important but complex issue in modern web development. conventional try-catch
Although statements are powerful, they can easily lead to lengthy and difficult to maintain code.
To simplify this process,ECMAScript
A new proposal has recently been introduced:proposal-safe-assignment-operator
The ‘Safe Assignment Operator’ is denoted as?=
)。
Summary of Proposal
Secure assignment operator?=
The goal is to simplify error handling.
It handles errors by converting the result of a function into an array.
If the function throws an error, the operator returns
[error, null]
;If the function is successfully executed, return
[null, result]
。
This operator andPromise、async
Functions and any implementationSymbol.result
The values of the method are compatible.
For example, when executingI/O
Operation or based onPromise
During API interaction, unexpected errors may occur at runtime.
If these errors are ignored, it may lead to unexpected behavior and potential security vulnerabilities. Using secure assignment operators can effectively handle these errors:
const [error, response] ?= await fetch("https://blog.conardli.top");
Motivation for Proposal
Simplify error handling : By eliminating
try-catch
Block, simplify error management process;Enhance code readability Reduce nesting, improve code clarity, and make the error handling process more intuitive;
Cross API consistency Establish a unified error handling method across different APIs to ensure behavioral consistency;
Improve security Reduce the risk of ignoring error handling, thereby enhancing overall code security.
Example usage
The following is a typical example of not using?=
Example of error handling for operators:
async function getData() {
const response = await fetch("https://blog.conardli.top");
const json = await response.json();
return validationSchema.parse(json);
}
The above function has multiple points that may have anomalies (e.gfetch()、json()、parse()
)We can use?=
Operators are processed in a very concise and easy to read manner:
async function getData() {
const [requestError, response] ?= await fetch("https://blog.conardli.top"); if (requestError) {
handleRequestError(requestError);
return;
} const [parseError, json] ?= await response.json(); if (parseError) {
handleParseError(parseError);
return;
} const [validationError, data] ?= validationSchema.parse(json); if (validationError) {
handleValidationError(validationError);
return;
} return data;
}
Proposal function
Symbol.result
Any implementation has been madeSymbol.result
The objects of the method can all be related to?=
Use operators together.
Symbol.result
The method must return an array, where the first element represents the error and the second element represents the result.
function example() {
return {
[Symbol.result]() {
return [new Error( An error has been reported ), null]
},
}
}const [error, result] ?= example() // Function.prototype also implements Symbol.result
// const [error, result] = example[Symbol.result]()// error is Error('123')
Safe assignment operator (?=)
?=
The operator calls the object or function on the right side of the operatorSymbol.result
Method to ensure consistent handling of errors and results in a structured manner.
const obj = {
[Symbol.result]() {
return [new Error("Error"), null]
},
}const [error, data] ?= obj
// const [error, data] = obj[Symbol.result]()
function action() {
return 'data'
}const [error, data] ?= action(argument)
// const [error, data] = action[Symbol.result](argument)
The results should comply with[error, null | undefined]
or[null, data]
The format.
When used in a function?=
When using an operator, all parameters passed to the function will be forwarded toSymbol.result
method.
declare function action(argument: string): stringconst [error, data] ?= action(argument1, argument2, ...)
// const [error, data] = action[Symbol.result](argument, argument2, ...)
When?=
When used with an object, operators do not pass any parameters toSymbol.result
method.
declare const obj: { [Symbol.result]: () => any }const [error, data] ?= obj
// const [error, data] = obj[Symbol.result]()
Recursive processing mechanism
in use[error, null]
When encountering an array, the first exception will be generated. However, if[null, data]
The data in the array has also been implementedSymbol.result
Method, then the method will be recursively called.
const obj = {
[Symbol.result]() {
return [
null,
{
[Symbol.result]() {
return [new Error("Error"), null]
},
},
]
},
}const [error, data] ?= obj
// const [error, data] = obj[Symbol.result]() //Error is Error ('string ')
This behavior helps to handle various situations that includeSymbol.result
Methods ofPromise
Or object:
async function(): Promise<T>
function(): T
function(): T | Promise<T>
Handling Promise
Promise
ExceptFunction
Besides, the only way to?=
The implementation of using operators together.
const promise = getPromise()
const [error, data] ?= await promise
// const [error, data] = await promise[Symbol.result]()
You may have already noticedawait
and?=
Can be used together and absolutely no problem. Due to their recursive processing characteristics, they can be well combined together.
const [error, data] ?= await getPromise()
// const [error, data] = await getPromise[Symbol.result]()
The execution sequence is as follows:
getPromise[Symbol.result]()
When called, an error may be thrown (if it is a synchronous function that returns a Promise).If an error is thrown, it will be assigned to
error
And the execution will stop.If no errors are thrown, the result will be assigned to
data
. becausedata
It is a promise, and the promise hasSymbol.result
Method, so it will be recursively processed.If the Promise is rejected, the error will be assigned to
error
And the execution will stop.If the Promise is resolved, the result will be assigned to
data
。
Through this recursive processing mechanism, you can simplify the handling of various complex nested objects and promises, making the code more concise and easy to read.
Polifll
This proposal is still in its early stages and it will take a long time to enter the standard. Currently, it is necessary to use thispolifill
:
https://github.com/arthurfiorette/proposal-safe-assignment-operator/blob/main/polyfill.js
However,?=
The operator itself cannot be directly appliedpolyfill
. When targeting older onesJavaScript
In the environment, a compiler is required to?=
Convert operators to their corresponding[Symbol.result]
Call.
const [error, data] ?= await asyncAction(arg1, arg2)
// should become
const [error, data] = await asyncAction[Symbol.result](arg1, arg2)const [error, data] ?= action()
// should become
const [error, data] = action[Symbol.result]()const [error, data] ?= obj
// should become
const [error, data] = obj[Symbol.result]()
Proposal address: https://github.com/arthurfiorette/proposal-safe-assignment-operator