Let's say we have this buggy function:
async function buggy() {
while(true) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
If you call it somewhere in NodeJS, would it permanently impact the server performances ?
If so, would it be better to always put a fail-safe mechanism like so for all untrusted promises:
new Promise((resolve, reject) => {
buggy().then(() => resolve);
setTimeout(reject, 10000);
};
No, there is nothing wrong with your buggy function. To say that a promise runs is misleading: a promise doesn't run. It is an object that has provided a callback. As long as that callback resolve isn't called, and its then method isn't called, there is nothing happening with that promise object.
The following happens when buggy is run:
new Promise creates a promise objectsetTimeout is run and completes immediately. It registers the resolve callback.await is executed, which actually calls then on the above promise to add a listener, and makes buggy return. If this is the first time, then it returns a pending promise to the caller.buggy), the setTimeout API will put the resolve callback on the relevant job queue.resolve callback) puts the promise in a resolved state and puts a notification for its then-listeners (including the one created by await) as a job on the promise job queue.buggy, which then continues with its loop.The impact on the engine or memory is comparable with a setInterval call that you never clear with clearInterval. There is just a little bit more overhead due to the extra promise related jobs (in addition to the regular timer job) that kick in after each second, and the saved execution state of buggy, which is comparable with what you would have with an infinite generator (using yield).
In the case that the promise resolve state depends on an external resource / timer that never ends (Infinity as the duration) the suggested fail-safe would work and the server performance wouldn’t be affected so much.
// this won’t stuck and the fail-safe will work
// (ignore the timer not being cleaned)
function buggy() {
return new Promise(resolve => setTimeout(resolve, Infinity));
}
Otherwise (in case the promise is solely synchronous, i.e. the resolve depends on an infinite loop that never ends) the reject function would never get called as the event loop is stuck which will stuck the server.
// The fail-safe wouldn’t work and the server is stuck
async function buggy() {
while(true);
}
Edit: As pointed out by @Vlaz, in case the buggy function is similar to this:
async function buggy() {
while(true) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
The fail-safe would work and the server won’t stuck.
Edit 2: In both cases you won't need a fail safe because if a the fail safe would work it means that the code doesn't stuck the Event Loop and also calling reject on the promise doesn't abort the buggy one