Node.js异步任务是否同步处理?

时间:2014-08-20 05:56:59

标签: javascript node.js asynchronous

考虑以下代码:

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启动三个异步函数,仍然是零延迟,是第二个我开始保证在第一个完成后运行,第三个保证在第二个完成后启动吗?

4 个答案:

答案 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

  

我理解的是,在同步执行事件循环时,启动的异步任务(无论来源如何)都按照调用它们的顺序同步执行?

是的,你是对的。