蓝鸟的超时有多快/多高效?



在大多数情况下以下示例时间(输出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() === falseret.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。

相关内容

  • 没有找到相关文章

最新更新