[英]Understanding the event loop and partitioning in Node.js
我读过这个很好的文档指南: https://nodejs.org/en/docs/guides/dont-block-the-event-loop/
在那篇文章的某些部分,有人说是在不阻塞事件循环的情况下进行复杂计算:
假设您想在不阻塞事件循环的情况下在 JavaScript 中进行复杂的计算。 您有两个选择:分区或卸载。 您可以对计算进行分区,以便每个计算都在事件循环上运行,但定期产生(轮流)其他未决事件。
他们以这个代码示例为例来计算 0 + 1 + 2 +... + n 的平均值:
function asyncAvg(n, avgCB) {
// Save ongoing sum in JS closure.
var sum = 0;
function help(i, cb) {
sum += i;
if (i == n) {
cb(sum);
return;
}
// "Asynchronous recursion".
// Schedule next operation asynchronously.
setImmediate(help.bind(null, i+1, cb));
}
// Start the helper, with CB to call avgCB.
help(1, function(sum){
var avg = sum/n;
avgCB(avg);
});
}
asyncAvg(n, function(avg){
console.log('avg of 1-n: ' + avg);
});
我的问题是:
setImmediate
将被执行如果轮询阶段脚本已被setImmediate()
调度,则事件循环将结束轮询阶段并继续到检查阶段以执行那些调度的脚本。
但是如果我们在递归步骤中:
function help(i, cb) {
sum += i;
if (i == n) {
cb(sum);
return;
}
// "Asynchronous recursion".
// Schedule next operation asynchronously.
setImmediate(help.bind(null, i+1, cb));
}
那么 poll 应该是空的,但是setImmediate
命令,因此它应该继续运行递归,那么它如何给其他代码同时执行的机会呢? 在事件循环调度方面。
n
没有RangeError: Maximum call stack size exceeded
错误,但是如果我更改此行:setImmediate(help.bind(null, i+1, cb));
到这一行:
help(i+1, cb);
然后错误RangeError: Maximum call stack size exceeded
弹出。 我的意思是,使用setImmediate
无论如何都应该保留由递归引起的函数堆栈,不是吗?
那么 poll 应该是空的,但是 setImmediate 命令,因此它应该继续运行递归,那么它如何给其他代码同时执行的机会呢?
因为setImmediate
将回调安排在poll
阶段完成后发生。 这些回调在check
阶段运行。 在check
期间添加更多回调会安排它们,但不会导致它们运行; 下次循环进入poll
阶段时会发生这种情况,看到有挂起的回调,然后进入check
阶段。
为什么对于非常大的 n 没有 RangeError: Maximum call stack size exceeded 错误
因为递归不是立即的,所以它不会消耗堆栈空间。 setImmediate
只是安排一个回调,它不调用回调。 您的代码结束,释放其堆栈资源,并且事件循环继续。 稍后,您通过setImmediate
安排的回调将运行,短暂地使用少量堆栈空间。
相反,当您立即调用help
时,这是分配一个新的堆栈帧,如果您使用大的n
,则分配的堆栈帧过多并用完堆栈。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.