How do you catch errors in async code?
Inside an async function you use the ordinary try and catch, but you have to await the call inside the try block. A rejected promise only throws when you await it, so a try block that calls the function without awaiting will not catch anything.
async function risky() {
throw new Error("boom");
}
// A promise chain handles the rejection explicitly.
risky()
.then(() => console.log("not reached"))
.catch((err) => console.log("caught in the chain:", err.message));
// try and catch works when you await the call.
(async () => {
try {
await risky();
} catch (err) {
console.log("caught with await:", err.message);
}
})();There is a subtlety in that snippet that is worth spelling out. The first call is not awaited, but it is not a leak either, because the catch handler is attached to the chain in the same tick. The rule is not that every call must be awaited. The rule is that every promise must end up with a rejection handler somewhere, and the two ways to do that are to await it inside a try block or to attach a catch handler.
For code that mixes several operations, the try and catch around a block of awaits is usually the clearest form. If you want to run a step and ignore its failure without stopping the rest, wrap that step individually so the error is handled where it happens.
One more pattern worth knowing is the finally method, which runs its callback whatever happened. It is the right place for cleanup such as hiding a loading spinner, and it does not swallow the error, because it runs before the rejection continues up the chain.