使用process.nextTick或setImmediate创建等待函数 - node.js

时间:2015-05-18 20:22:15

标签: javascript node.js recursion

我正在编写一些Node.js,我想,来自Java背景,我应该弄清楚如何创建自己的"等待"功能。显然,它会有所不同,因为Java被设计为多线程而Node不是。无论如何,在Node中我想要的功能是我想自己创建一个阻塞函数 - 这样如果程序中的某个布尔值没有设置,我可能想调用process.nextTick()直到布尔值被设置。

所以它会是:

    var bool = false;

    function foo(){
    var b = baz();
    }

    function baz(){

        while(!bool){
           process.nextTick(function() {
           return baz(arguments);
        });
      }

    return {};
    }

   function setBool(number) {

       setTimeout(function () {
            bool = false;
       }, number);
   }

   process.nextTick(wait);
   setBool(3000);

所以这个问题有两个方面:

(1)这是在Node.js中实现等待类型功能的最佳方法吗?

(2)如果我调用baz(参数)而不是baz函数(递归地)执行会发生什么?通常,当你想要函数X的返回值,但函数X在返回之前调用自己几次,这是否会造成任何问题?这没什么大不了的,结果是相同的回报价值?我之前已经考虑过这个问题,但从未真正担心或调查过它。

3 个答案:

答案 0 :(得分:5)

不要等待'在Node.js. "等待"阻止所有其他执行。这是一个重要的注意事项,因为如果你阻止,那么布尔值永远不能设置改变。 JavaScript,特别是在Node中,使用事件驱动模型。这样做,那时。

那么最好的方法呢?它是基于意见的,但这是一种方式:

var bool = false;

function foo() {
    console.log('Listening for true');
    baz(function() {
        //Do something when called
        console.log('It\'s finally true!');
    });
}

function baz(callback) {
    setImmediate(function() {
        if (bool)
            callback();
        else
            baz(callback);
    });
}

foo();
setTimeout(function() {
    console.log('Setting to true');
    bool = true;
}, 4000);

答案 1 :(得分:5)

其他答案已经说明了重要的部分:不,这不会奏效。我想发布这个内容,以提供更多关于为什么这不起作用的背景信息。

在幕后,node.js正在运行一个事件调度循环。存在一系列事件(包括,至少在概念上,“app start”,“incoming message”,“socket connection”,“file io complete”等)。当事件发生时,事件调度程序将事件从队列中拉出并调用与该事件关联的任何Javascript函数。一旦回调函数完成,调度就会将下一个事件从队列中拉出,处理它等等。这是完全同步的 - 下一个事件在当前事件完成之前无法处理。

所以当你有这样的代码时:

var done = false;
while (!done) {
    process.nextTick(function () {
       done = true;
    });
}

会发生什么?您输入while循环,process.nextTick 将事件放在事件队列中,以便在下次运行事件循环时进行处理。然后您的代码循环返回while,检查完成(仍然为false)排队另一个事件等等。

由于事件循环在函数返回之前无法处理排队事件,因此事件循环会卡住,并且不会调用process.nextTick的回调。你已经确保永远不会有“nextTick”。

无法 在纯Javascript代码中执行同步等待。在Node.js中,您可以在C扩展中执行此操作(这就是fs.readFileSync之类的实现方式)。您可以使用一些Javascript编译器技巧(如streamlineco)来编写看起来同步的代码。但在引擎盖下,他们都使用异步回调模式。

我的建议是首先学习核心回调模式,以便你理解它。这是一种巨大的痛苦。从那里调查promises(我个人喜欢Bluebird作为promise实现,或者如果你使用的是ES6,你可以使用内置的promises)或许多异步帮助库之一。

答案 2 :(得分:1)

在Javascript中执行此操作的典型方法是使用promises。例如,使用“q”承诺(参见https://github.com/kriskowal/q),您将拥有:

var deferred = Q.defer();


deferred.promise.then(function(myParam) {
    var b = baz();
});
function baz(){
    return {/*whatever you want*/};
}

而且,代码中的其他地方:

deferred.resolve(myParam);

在此示例中,您确保仅在满足某些条件后才调用“baz”。基本上,不是将布尔值设置为true,而是“解析”延迟对象。