The following example times out in most cases (outputs timed out
):
Promise = require('bluebird');
new Promise(resolve => {
setTimeout(resolve, 1000);
})
.timeout(1001)
.then(() => {
console.log('finished');
})
.catch(error => {
if (error instanceof Promise.TimeoutError) {
console.log('timed out');
} else {
console.log('other error');
}
});
Does this mean that the Bluebird's promise overhead takes longer than 1ms?
I see it often time out even if I use .timeout(1002)
.
The main reason for asking - I'm trying to figure what the safe threshold is, which gets more important with smaller timeouts.
Using Bluebird 3.5.0, under Node.js 8.1.2
I have traced your bug in Bluebird's code. Consider this:
const p = new Promise(resolve => setTimeout(resolve, 1000));
const q = p.timeout(1001); // Bluebird spawns setTimeout(fn, 1001) deep inside
That looks rather innocent, yeah? Though, not in this case. Internally, Bluebird implemented it something like (not actually valid JS; timeout clearing logic is omitted):
Promise.prototype.timeout = function(ms) {
const original = this;
let result = original.then(); // Looks like noop
setTimeout(() => {
if result.isPending() {
make result rejected with TimeoutError; // Pseudocode
}
}, ms);
return result;
}
Bug was presence of line ret.isPending()
. It resulted in brief time when original.isPending() === false
and ret.isPending() === true
because "resolved" status didn't propagate yet from original
to children. Your code hit that extremely short period and BOOM, you had race condition.