Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
732 views
in Technique[技术] by (71.8m points)

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

There is a common anti pattern in JavaScript:

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

function f() {
    try {
        fs.readFile('data', 'utf8', handleDataClb);
    } catch(e) {
        // handle error... 
    }
}

This try-catch in f will not catch errors in the handleDataClb as the callback is called in a later stage and context where the try-catch is not visible anymore.

Now in JavaScript async-await is implemented using generators, promises, and coroutines, as in:

// coroutine example 
co(function* doTask() {
    try {
        const res1 = yield asyncTask1(); // returns promise
        const res2 = yield asyncTask2(); // returns promise
        return res1 + res2;
    } catch(e) {
        // handle error... 
    }
});

// async-await example
async function doTask() {
    try {
        const res1 = await asyncTask1(); // returns promise
        const res2 = await asyncTask2(); // returns promise
        return res1 + res2;
    } catch(e) {
        // handle error... 
    }
}

This way the try-catch works, which is often mentioned as one great advantage of async-await over callbacks.

Why and how does the catch work? How does the coroutine aka async manage to throw the error inside the try-catch when one of the asyncTask calls results in a promise rejection?

EDIT: as others have pointed out, the way how the JavaScript engine implements the await operator can be very different from the pure JavaScript implementation used by transpilers like Babel and shown above as coroutine example. Therefore to be more specific: how is this working using native JavaScript?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Why and how does the catch work? How does the coroutine aka async manage to throw the error inside the try-catch?

A yield or await expression can have 3 different outcomes:

  • It can evaluate like a plain expression, to the result value of that
  • It can evaluate like a throw statement, causing an exception
  • It can evaluate like a return statement, causing only finally statements to be evaluated before ending the function

On a suspended generator, this can be achieved by calling either the .next(), .throw() or .return() methods. (Of course there's also a 4th possible outcome, to never get resumed).

…when one of the asyncTask calls results in a promise rejection?

The awaited value will be Promise.resolve()d to a promise, then the .then() method gets invoked on it with two callbacks: when the promise fulfills, the coroutine is resumed with a normal value (the promise result), and when the promise rejects, the coroutine is resumed with an abrupt completion (exception - the rejection reason).

You can look at the co library code or the transpiler output - it literally calls gen.throw from the promise rejection callback.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...