try-catch doesn’t catch an error thrown in timer friend functions setTimeout
, setInterval
and setImmediate
.
Using timer function alone
This code doesn’t work. As you can see, its process dies.
try {
global.setTimeout(() => {
console.log("internal process1 working...");
throw new Error("throw an error1");
}, 1000);
} catch (e) {
console.log(e.message);
}
// internal process1 working...
// ...\src\simple-code\timers\app.ts:5
// throw new Error("throw an error1");
// ^
// Error: throw an error1
// at Timeout._onTimeout (...\src\simple-code\timers\app.ts:5:15)
// at listOnTimeout (internal/timers.js:554:17)
// at processTimers (internal/timers.js:497:7)
// npm ERR! code ELIFECYCLE
// npm ERR! errno 1
// npm ERR! simple-code@1.0.0 start-timer: `ts-node ./timers/app.ts`
// npm ERR! Exit status 1
// npm ERR!
// npm ERR! Failed at the simple-code@1.0.0 start-timer script.
// npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
// npm ERR! A complete log of this run can be found in:
// npm ERR!
It’s because the callback for the timer friend function isn’t in the same context when it’s triggered. The callback is pushed into a queue and called there.
There are two ways to solve this problem. First one is to define uncaughtException
event callback if it is running on Node.js.
process.on("uncaughtException", (e) => {
console.log(e.message)
});
// internal process1 working...
// throw an error1
However, this code catches all uncaught Exceptions. It is not handy.
Second way is to define try-catch in the timer function.
global.setTimeout(() => {
try {
console.log("internal process2 working...");
throw new Error("throw an error2");
} catch (e) {
console.error(e.message);
}
}, 1000);
//internal process2 working...
// throw an error2
Timer function with Promise
You use timer function with Promise if you want to do something after its callback process finishes. Following code doesn’t work.
const promise = new Promise((_, reject) => {
global.setTimeout(() => {
console.log("internal process3 working...");
throw new Error("throw an error3");
}, 1000);
});
promise.catch((e) => {
console.log(`error caught in promise.catch.`);
console.log(e.message);
});
// internal process3 working...
// ...\src\simple-code\timers\app.ts:22
// throw new Error("throw an error3");
// ^
// Error: throw an error3
// at Timeout._onTimeout (...\src\simple-code\timers\app.ts:22:19)
// at listOnTimeout (internal/timers.js:554:17)
// at processTimers (internal/timers.js:497:7)
// npm ERR! code ELIFECYCLE
// npm ERR! errno 1
// npm ERR! simple-code@1.0.0 start-timer: `ts-node ./timers/app.ts`
// npm ERR! Exit status 1
// npm ERR!
// npm ERR! Failed at the simple-code@1.0.0 start-timer script.
// npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
// npm ERR! A complete log of this run can be found in:
// npm ERR!
Call reject function instead when it throws an error.
const promise = new Promise((_, reject) => {
global.setTimeout(() => {
try {
console.log("internal process4 working...");
throw new Error("throw an error4");
} catch (e) {
reject(e);
}
}, 1000);
});
promise.catch((e) => {
console.log(`error caught in promise.catch.`);
console.log(e.message);
});
// internal process4 working...
// error caught in promise.catch.
// throw an error4
Summary
Enclose your code with try-catch in the timer friend function.
Call reject function if you call it in Promise.
Comments