node.js:while 循环回调未按预期工作

Posted

技术标签:

【中文标题】node.js:while 循环回调未按预期工作【英文标题】:node.js: while loop callback not working as expected 【发布时间】:2012-10-03 20:15:08 【问题描述】:

知道 Node.js 是异步工作时,编写如下代码:

function sleep() 
    var stop = new Date().getTime();
    while(new Date().getTime < stop + 15000) 
        ;
    


sleep();
console.log("done");

...会调用 sleep(),在 while 循环期间(15 秒)阻塞服务器,然后将“完成”打印到控制台。据我了解,这是因为 Node.js 只允许 javascript 访问主线程,因此这件事会停止进一步的执行。

所以我知道解决方案是使用回调:

function sleep(callback) 
    var stop = new Date().getTime();
    while(new Date().getTime() < stop + 15000) 
        ;
    
    callback();


sleep(function() 
    console.log("done sleeping");
);

console.log("DONE");

所以我认为这会在 15 秒后打印“完成”。 '完成睡眠',因为 sleep() 函数被调用并被传递一个指向回调函数的指针。当这个函数工作时(while 循环),最后一行将被执行(打印 'done')。 15 秒后,当 sleep() 函数完成时,它会调用给定的回调函数,然后打印“完成睡眠”。

显然我在这里理解了一些错误,因为上述两种方式都阻塞了。有人可以澄清一下吗?

提前致谢, 斯拉格约科

【问题讨论】:

【参考方案1】:

Javascript 和 node.js 是单线程的,这意味着一个简单的while 块;在while 块完成之前,不能处理任何请求/事件。回调并不能神奇地解决这个问题,它们只是帮助将自定义代码传递给函数。相反,使用process.nextTick 进行迭代,这将为您提供基本相同的结果,但也为要处理的请求和事件留出了空间,即它不会阻塞:

function doSleep(callback) 
    var stop = new Date().getTime();

    process.nextTick(function() 
        if(new Date().getTime() < stop + 15000) 
            //Done, run callback
            if(typeof callback == "function") 
                callback();
            
         else 
            //Not done, keep looping
            process.nextTick(arguments.callee);
        
    );


doSleep(function() 
    console.log("done sleeping");
    console.log("DONE");
);

【讨论】:

你把自己弄复杂了。一个简单的 setTimeout(callback, delay) 应该足以产生与异步指示相同的内容。 @FabiánH.jr.关键是 OP 可能有兴趣了解为什么他的while 不起作用以及如何以非阻塞方式编写while,恕我直言,这比“你的方法无关紧要”更好不行,换个方法吧”。 好吧,总体来说很好的答案,现在你提到它,它在 node.js 的内部过程中非常有见地 有趣的是,我知道单独的 while 循环会阻止脚本执行其他操作,因为它正在在一个线程中运行。出于某种原因,我认为节点会识别阻塞代码,如果我用回调调用它,它只会让它工作并在完成后返回它,同时执行最后一行。当然,这是无意义的,因为只有一个线程可以工作,而且由于节点当然 not '看到'有一个繁忙的循环,它不会移动这个函数进入一个单独的线程,因此主线程被阻塞。 因此 process.nextTick 在事件循环的下一个滴答声中逐字执行给定的函数,让其他排队的任务,例如应该打印“完成”的最后一行,在脚本停止之前执行15 秒循环的下一个刻度。因此,假设我们将循环 5 毫秒,并且在该循环之外还有 5 个其他任务要完成,我猜使用 process.nextTick 将执行排队的任务 #1,然后执行 5 毫秒循环的一个滴答声,然后是任务 #2,依此类推对吧?【参考方案2】:

您立即调用sleep,新的sleep 功能块。它不断迭代,直到满足条件。你应该使用setTimeout() 来避免阻塞:

setTimeout(function () 
    console.log('done sleeping');
, 15000);

【讨论】:

【参考方案3】:

回调与异步不同,它们只是在您想从异步操作中获取...回调时很有帮助。在您的情况下,该方法仍然同步执行; Node 不只是神奇地检测到有回调和长时间运行的操作,并使其提前返回。

真正的解决方案是使用setTimeout,而不是另一个线程上的繁忙循环。

【讨论】:

【参考方案4】:

如前所述,异步执行应该通过 setTimeout() 而不是 while 来实现,因为 while 会冻结在一个“执行帧”中。

您的示例中似乎还有语法错误。

这个很好用:http://jsfiddle.net/6TP76/

【讨论】:

以上是关于node.js:while 循环回调未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

Node.js express.json 中间件未按预期解析请求

Node.js 事件循环

文件输入未按预期工作

for(i=0;i<number;i++) 循环行为未按预期工作?

Node.js 事件循环

Node.js 事件循环