【问题标题】:nodejs: wait for other methods to finish before executingnodejs:在执行之前等待其他方法完成
【发布时间】:2013-08-09 14:16:23
【问题描述】:

说我有两种方法:

function A(callback) { ... }
function B(callback) { ... }

我要执行:
函数 C();
在 A 和 B 都完成后。
我们通常做的是将函数 C 放在回调中,例如:

A(function() {
  B(function() {
    C();
  });
});

现在如果 A 和 B 都需要很长时间,我不希望 B 在 A 完成后执行。相反,我想同时启动它们以提高性能。
我在想的是实现类似信号量的东西(当然不是真正的信号量),它在 A 和 B 都完成后触发一个事件。这样我就可以在事件中调用 C。

我想知道的是,是否有任何库已经实现了上述功能?我相信我不是第一个想要这样做的人。
任何帮助表示赞赏。

【问题讨论】:

标签: javascript node.js


【解决方案1】:

扩展我的评论...

async 是一个用于 Node.js 的 commonly used 异步流控制库。

它的async.parallel() 可能会很好地解决这个问题:

async.parallel([
    function(done) {
        A(function () {
            done(null);
        });
    },

    function(done) {
        B(function () {
            done(null);
        });
    }
], function (err) {
    C();
});

这可能会被缩短,但这取决于每个函数如何与回调交互以及它们是否遵循error-first 回调的常见 Node.js 模式:

async.parallel([A, B], C);

【讨论】:

  • 我找到了另一个库github.com/creationix/step,看来他们也在做同样的事情。无论如何,这解决了我的问题。谢谢。
【解决方案2】:

为了完整起见,如上所述,使用外部对象来保持完成状态可以实现相同的结果,其中 A() 和 B() 检查另一个是否已完成,如果是,则调用 C ()。如:

var results={};

function onComplete(){
    if(results['A'] && results['B'] && !results['C']) {
        C();
    }
}

function A(){
    // ... 
    results['A']=true;
    onComplete();
}

function B(){
    // ... 
    results['B']=true;
    onComplete();
}

可以通过在 A() 和 B() 中添加“isComplete”标志来替换结果对象,如下所示:

function A(){
    // ...
    A.isComplete=true;
    onComplete();
}

并修改 onComplete 以检查这个新标志:

function onComplete(){
    if(A.isComplete && ...
}

或者,同样使用事件:

var util=require('util'),
    events=require('events'),
    EventEmitter=events.EventEmitter;

function F(){
    EventEmitter.call(this); // init ancestor
}

util.inherits(F,EventEmitter); // assign ancestor

F.prototype.A=function(){
    var self=this;
    console.log('running A()');
    setTimeout(function(){ // simulate long running code - 5 seconds
        F.prototype.A.isComplete=true;
        self.emit('complete','A');
    },5000);
};

F.prototype.B=function(){
    var self=this;
    console.log('running B()');
    setTimeout(function(){ // simulate long running code - 3 seconds
        F.prototype.B.isComplete=true;
        self.emit('complete','B');
    },3000);
};

F.prototype.C=function(){
    console.log('running C()');
};

var f=new F;
f.on('complete',function(which){ // onComplete handler
    console.log(which+'() is complete');

    if(F.prototype.A.isComplete && F.prototype.B.isComplete){
        f.C();
    }
});

// start it up
f.A();
f.B();

运行时会产生:

>node example.js
running A()
running B()
B() is complete
A() is complete
running C()
>

【讨论】:

    【解决方案3】:
    async.parallel([
        function(){ ... },
        function(){ ... }
    ], callback);
    

    来自:https://github.com/caolan/async

    所以在你的情况下:

    async.parallel([funcA,funcB],funcC);
    
    //function definitions
    function funcA() {...}
    function funcB() {...}
    function funcC() {...}
    

    如果没有模块,我猜它看起来像这样:

    var numFuncs = 2;
    A(D);
    B(D);
    
    and then 
    function D() {
    if(numFuncs==0){ C(); } else {
    numFuncs--; 
    }}
    

    或者像这样:

    A(D(C));
    B(D(C));
    
    
    function D() {
        var x = process.funcsToCall= process.funcsToCall || {};
        var f=arguments[0];
        (!x.hasOwnProperty(f.name))?x[f.name]=0:x[f.name]++;
        return function(){
           (x[f.name]==0)?f():x[f.name]--;
        }
    }
    

    【讨论】:

    • 第一手册更可靠,因为如果A 在 B 甚至有时间开始之前调用它的回调 D。或者不是我不确定。
    【解决方案4】:

    如果你在 ES6 上运行,你可以使用Promise.all。这是重写的示例代码:

    Promise.all([
      new Promise((resolve) => A(() => resolve())),
      new Promise((resolve) => B(() => resolve())),
    ]).then(() => {
      C()
    }).catch(err => {
      // handle errors from function A, B and C
    })
    

    【讨论】:

      【解决方案5】:

      我们可以为此目的ayncawait,例如:

      async function Foo(){
         // function logic
      }
      

      这个 Foo 函数为:

      await Foo();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-07
        • 2021-01-07
        • 2016-08-31
        • 1970-01-01
        • 2013-02-17
        • 1970-01-01
        • 2017-10-20
        • 1970-01-01
        相关资源
        最近更新 更多