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 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…