考虑以下代码:
var some_expensive_task = function(i) {
setTimeout(function() {
var a = 1;
while (a < 100000000) {
Math.sqrt(a);
++a;
}
console.log('finished set' + i);
}, 0);
};
for (var i = 0; i < 70; ++i) {
console.log('start ' + i);
some_expensive_task(i);
console.log('end ' + i);
}
这个程序的目的是使用setTimeout迭代并启动70个cpu密集型异步任务。
正如预期的那样,该程序的输出是:
start 1
end 1
...
start 69
end 69
finished set1
...
finished set69
在整个执行过程中,只有两个过程。我假设其中一个是空闲事件循环,另一个是100%运行的工作进程。
我理解的是,在同步执行事件循环时,启动的异步任务(无论来源如何)都按照调用它们的顺序同步执行?
更新
我仍然觉得我没有清楚地表达我的问题。使用setTimeout是我能想到的准确安排一堆异步函数运行的唯一方法。我想真正的问题是,如果我用setTimeout启动三个异步函数,仍然是零延迟,是第二个我开始保证在第一个完成后运行,第三个保证在第二个完成后启动吗?
答案 0 :(得分:2)
您在问题中使用了错误的术语,Are Node.js asynchronous tasks handled synchronously
没有多大意义。测试用例不是你想象的那样。首先明确一些术语:
保证同步函数按其调用顺序运行/完成。
异步函数可以进行调用并完成无序调用。
阻止操作是指一旦启动就必须完成的操作,以便执行进一步发展。除非在单独的worker上运行,否则CPU密集型操作将被阻止。循环本质上是阻塞的。一旦它们启动,它们将在执行下一个函数之前完成所有迭代。
setTimeout在当前时间之后至少调用传递函数至少x ms。调用它意味着一旦x ms通过它就会在事件循环中对传递的函数进行排队。这只是延迟执行。
因此,考虑到上述事实,这就是为什么您的测试具有误导性的原因:
首先,您的测试用例(您的CPU密集型函数)不是异步的,您将它包装在异步的setTimeout周围。超时0仅表示它们将按照调用它们的顺序执行。所有回调函数都是同步的。
其次,日志中的开始和结束表示调用setTimeout的位置。这将按预期顺序进行。超时0时,完成也将按顺序完成。是的,如果你保持超时等于他们,他们将按照通过的顺序执行。然后,这是许多可能的情况之一,其中结果类似于同步(如果超时按递增顺序怎么办?)。你问的问题可能适用于这些情况,但并非总是如此。
第三,如果你想模拟异步性(足以看到控制台上的无序行为),可以放松while循环并使用随机超时(Math.random()*1000
)。你会看到它们以任意方式完成。这将是异步执行(setTimeout而不是回调)。
答案 1 :(得分:1)
Node.js是单线程的,并且在一个进程中运行,因为JavaScript是单线程的。因此你是对的。
答案 2 :(得分:0)
是。 Javascript,包括NodeJS,是单线程的(除了少数例外)。
使用setTimeout(fn, 0)
时,它会将当前调用堆栈清除后运行的函数排队。在您的示例中,这意味着for
循环将在“昂贵任务”运行之前完成。
答案 3 :(得分:0)
您的JS代码在Node.js中的单个线程中运行。所有其他本机Node.js API都是用C / C ++编写的,可以是异步的,也可以在单独的线程上运行。 有关更详细的说明,请参阅this answer。
我理解的是,在同步执行事件循环时,启动的异步任务(无论来源如何)都按照调用它们的顺序同步执行?
是的,你是对的。