有没有办法检测事件循环代码运行在哪一轮?

问题描述 投票:0回答:2

为了更好地理解异步和纤程,我想知道是否有一个全局变量在事件循环的每一轮都会递增。

我希望能够看到在每个 console.log 语句中打印出不同的值,显然我们不能依赖系统时间来做到这一点。

function getEventLoopCounter () { /* magic occurs */ }

// Turn 1 
console.log("I'm on loop number: ", getEventLoopCounter());

// Turn > 1 
setTimeout(function(){
  console.log("I'm on different loop: ", getEventLoopCounter());
}, 0);
javascript node.js meteor
2个回答
4
投票

也许来自节点定时器模块

setImmediate可以工作。引用自
setImmediate
的文档:

安排 I/O 事件后“立即”执行回调 回调以及 setTimeout 和 setInterval 之前。返回一个 可以与clearImmediate()一起使用的immediateObject。 (可选)你 还可以将参数传递给回调。

即时回调按照它们出现的顺序排队 创建的。每个事件循环都会处理整个回调队列 迭代。如果您从正在执行的内部对立即数进行排队 回调,该立即事件在下一个事件循环之前不会触发 迭代。

使用函数闭包和递归,你可以这样做:

var eventLoopCounter = 0;
setImmediate(function incrementEventLoopCounter() {
  eventLoopCounter++;
  setImmediate(incrementEventLoopCounter);
});
// Logging the total number of iterations every second.
setInterval(function() {
  console.log('The event loop has finished '
               + eventLoopCounter
               + ' iterations.');
}, 1000);

顺便说一句,在

timers
模块文档的开头,它指出:

所有定时器函数都是全局函数。您不需要 require() 这个模块才能使用它们。

这就是为什么

setImmediate
无需
timers
模块即可工作。

我想我应该注意到,我尝试使用

process.nextTick
做类似的事情,但我收到了一个错误,前面有一系列有用的警告消息,这些消息将我指向上面的函数:

...
(node) warning: Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral.
(node) warning: Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral.

RangeError: Maximum call stack size exceeded

0
投票

使用 setImmediate 在 Node.js 中效果很好,但不幸的是它不是 JavaScript 的标准。

还有一种使用微任务的替代解决方案:

const getEventLoopCounter = (() => {
    let counter = 0;
    let pending = false;
    const next = typeof queueMicrotask === 'function' ?
        queueMicrotask :
        callback => Promise.resolve().then(callback); // shim for old browsers
    return () => {
        if (!pending) {
            pending = true;
            next(() => {
                pending = false;
                counter++;
            });
        }
        return counter;
    };
})();

(如果您需要跟踪任务,请使用

setTimeout
作为
next
功能)

从新循环访问时,此代码保证返回新值,反之亦然 - 如果我们尚未退出下一个循环,则它返回未更改的值。

但请注意,它无法给出确切的经过的周期数。例如,如果有 100 个周期没有访问 getEventLoopCounter,则其新值将仅比前一个大 1,而不是 100。

© www.soinside.com 2019 - 2024. All rights reserved.