Reputation:
I frequently use a pattern in NodeJS & JavaScript where I combine a timeout with another promise using Promise.race, like this...
let timer
let p1 = x => {
return new Promise((resolve, reject) => {
bSomeFunctionCall(x) ? resolve() : reject()
}).finally(() => { console.log('p1 done') })
}
let p2 = ms => {
return new Promise((resolve, reject) => {
timer = setTimeout(() => {
reject('timeout')
}, ms)
}).finally(() => { console.log('timeout done') })
}
let p3 = Promise.race([p1(v1), p2(3000)])
await p3.finally(() => {
console.log('race done')
clearTimeout(timer)
console.log('done')
})
EDIT: Typo, 'timer' is a variable in scope for clearing.
However, I never see the p2.finally() message unless it times out & rejects, which makes me wonder if every time I use this pattern I create an unfulfilled promise floating around out there... potentially thousands of them.
I'm wondering if clearTimeout() in p3 causes the promise to resolve and since resolve() isn't defined, it just quietly settles, but shouldn't I see p2's finally() call?
I don't understand how p2 can settle and not call it's finally() method.
How can I debug this to convince myself I'm not making a mess under the hood? I was hoping there's a way to examine the number of outstanding promises in a debug mode...
Upvotes: 0
Views: 802
Reputation: 40404
.finally(() => { console.log('timeout done') })
always gets called, unless you never reject
that Promise
, which happens because you're clearing the timeout apparently when Promise.race
is settled.
In your code you assign the timeout id to timer
but then issue clearTimeout
with timeout
variable, which isn't defined in that script. So I'm assuming you're clearing the p2
promise timeout, and since p1
finishes first, when you clear the timer p2
never gets settled.
So don't use clearTimeout
since doesn't make sense if you're using Promise.race
, and finally
will always be called on p2
Just for debugging purposes, you can override Promise
constructor to keep track of all promises.
Promise = class extends Promise {
static list = []
constructor(...args) {
let p = super(...args)
Promise.list.push(p)
return p;
}
};
// Promise.list (will contain all promises, filter by `pending`
You can also check this answer: View all pending promises in javascript
Upvotes: 0