Compare these 2 snippets:
try {
console.log('start')
const test = (() => {
console.log('inside')
const a = null;
a.c = 1
})()
console.log('end')
} catch (error) {
console.log('nvmnghia');
console.error(error);
}
// prints:
// start
// inside
// nvmnghia
// TypeError: set props of null
try {
console.log('start')
const test = (async () => { // Note the async without await
console.log('inside')
const a = null;
a.c = 1
})()
console.log('end')
} catch (error) {
console.log('nvmnghia');
console.error(error);
}
// prints:
// start
// inside
// end
// undefined, due to normal return
// Uncaught (in promise) TypeError: ...
// and no nvmnghia, which means the error wasn't caught indeed
Why does it behave this way? I'm surpise cuz my mental model for async
/promise has always been that the part before the first await
is run synchronously i.e. NOT scheduled in a microtask.
When your code is run synchronously, the errors get caught immediately by try/catch. When it is async, even if there is no await used, the function returns a promise, and errors are then instead handled by the error of the promise. These errors don't get caught by a try/catch, so you'll need to use .catch() or await.