在大多数情况下以下示例时间(输出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');
}
});
这是否意味着蓝鸟的承诺开销需要超过1毫秒?即使我使用.timeout(1002)
。
询问的主要原因 - 我试图弄清楚什么是安全的阈值,这在较小的超时范围内变得更加重要。
使用bluebird 3.5.0,在node.js 8.1.2
我已经在蓝鸟的代码中追踪了您的错误。考虑一下:
const p = new Promise(resolve => setTimeout(resolve, 1000));
const q = p.timeout(1001); // Bluebird spawns setTimeout(fn, 1001) deep inside
看起来很无辜,是吗?不过,在这种情况下不是。在内部,Bluebird实现了类似(实际上没有有效的JS;省略超时清除逻辑(:
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;
}
错误是线ret.isPending()
的存在。这导致了original.isPending() === false
和ret.isPending() === true
的短暂时间,因为"解决"状态尚未从original
传播到孩子。您的代码达到了极短的时间和繁荣时期,您的比赛状况。
我认为这里发生了什么事,即在Plospor链中所需的时间与.timeout()
的计时器之间有一场比赛。由于他们俩的时机都如此接近,有时会赢得胜利,有时是另一个胜利 - 它们是racy。当我运行该代码记录事件序列时,我会在不同的运行中获得不同的订购。确切的输出顺序是不可预测的(例如racy(。
const Promise = require('bluebird');
let buffer = [];
function log(x) {
buffer.push(x);
}
new Promise(resolve => {
setTimeout(() => {
log("hit my timeout");
resolve();
}, 1000);
}).timeout(1001).then(() => {
log('finished');
}).catch(error => {
if (error instanceof Promise.TimeoutError) {
log('timed out');
} else {
log('other error');
}
});
setTimeout(() => {
console.log(buffer.join("n"));
}, 2000);
有时会输出:
hit my timeout
finished
,有时它会输出:
hit my timeout
timed out
如评论中所述,如果始终通过Microtask执行.then()
(应该先于任何宏观施法(,那么人们会认为.then()
会先于.timeout()
的CC_11,但事项显然并不那么简单。<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<</p>
,由于规范不规定Promise .then()
调度的详细信息(仅堆栈清除了应用程序代码(,代码设计不应假设特定的调度算法。因此,超时接近异步操作的执行可能是遵循的,因此可能是不可预测的。
如果您可以准确地解释要解决的问题,我们可能可以为做什么提供更多具体建议。JavaScript中的任何计时器都不是MS的精确性,因为JS是单线线程,所有计时器事件都必须遍历活动队列,并且在维修活动时,他们只能拨打他们的回调(不完全是计时器射击时(。也就是说,计时器事件将始终按顺序进行,因此setTimeout(..., 1000)
始终将在setTimeout(..., 1001)
之前出现,即使执行两个回调之间可能不完全有1ms的delta。