Why is it possible to try-catch an async-await call?

后端 未结 2 2029
时光说笑
时光说笑 2021-01-13 22:30

There is a common anti pattern in JavaScript:

function handleDataClb(err, data) {
    if(!data) throw new Error(\'no data found\');
    // handle data... 
}          


        
2条回答
  •  滥情空心
    2021-01-13 22:54

    async funtions

    An async function returns a promise that is resolved by a value returned by the function body, or rejected by an error thrown in the body.

    The await operator returns the value of a fulfilled promise or throws an error, using the rejection reason, if the awaited promise is rejected.

    Errors thrown by await can be caught by try-catch blocks inside the async function instead of allowing them to propagate up the execution stack and rejecting the promise returned by calling the async function.

    The await operator also stores the execution context before returning to the event loop, in order to allow promise operations to proceed. When internally notified of settlement of the awaited promise, it restores the execution context before proceeding.

    A try/catch block set up in the async function's execution context is not altered or rendered ineffective simply because the context has been saved and restored by await.

    As an aside

    "async-await is implemented using generators, promises, and coroutines"

    may be part of how Babel transpiles async function and await operator usage, but native implementations could be implemented more directly.


    Generator functions (Update)

    A generator function's execution context is stored in its associated generator object's internal [[Generator Context]] slot. (ECMA 2015 25.3.2)

    Yield expressions remove the generator's execution context from the top of the execution context stack (25.3.3.5 of ES6/ECMAScript 2015)

    Resuming a generator function restores the the function's execution context from the generator object's [[Generator Context]] slot.

    Hence generator functions effectively restore the previous execution context when a yield expression returns.

    Throwing an error within a generator function for normal reasons (syntax error, a throw statement, calling a function which throws) can be caught by a try-catch block as expected.

    Throwing an error by means of Generator.prototype.throw() throws an error within the generator function, originating from the yield expression that last passed control from the generator function. This error can be trapped by try-catch as for ordinary errors. (Refs MDN using throw(), ECMA 2015 25.3.3.4

    Summary

    Try-catch blocks around yield statments used in await transpilation code work for the same reason they do around await operators within native async functions - they are defined in the same execution context as the error is thrown for a rejected promise.

提交回复
热议问题