如何使用nodeJS中的eventEmitter解决外部的承诺?

时间:2016-10-16 19:44:11

标签: javascript node.js promise eventemitter

首先我要说的是,我对Node非常陌生,可能会出现设计错误,但我无法找到更好的方法来做我想要的事情。

我有一个需要迭代数组的函数,对于数组中的每个元素,它需要做一些异步工作。

我不希望函数的调用者继续处理,直到处理完数组中的所有元素,因此我将函数包装在Promise中,只有当所有元素的工作完成时才会解析。

我在我的函数中使用eventEmitter ,以便在完成对1个元素的工作时发出信号,现在我们可以开始处理下一个元素了。

处理完所有元素array.length==0后,承诺得以解决。

我遇到的问题是我的事件监听器在函数内部,并且每次函数运行时都会创建。另一方面,我无法将其置于功能之外,因为那时我无法解决我的功能承诺。

任何人都可以帮我弄清楚如何避免创建不必要的侦听器并保持我的功能正常工作吗?

我在创建侦听器时尝试使用.once()而不是.on()。它似乎没有解决问题...

function myFunc(objectToTest, testArray) {
    return new Promise(function (resolve, reject) {
        var array = [];

        for (let i = 0 ; i < testArray.length ; i++){
            if (objectToTest.name == testArray[i].name){
                array.push(testArray[i]);   
            }

        }


        eventEmitter.on('done-with-async-work', processArray);
        eventEmitter.emit('done-with-async-work')

        function processArray() {

            if (array.length > 0) {
                let itemInArray = array.shift();
                // some Async function
                auxFunc.asyncFunc(itemInArray).then(function (asyncResult)){
                    // Triggered when asyncFunc promise is resolved
                    eventEmitter.emit('done-with-async-work')
                }
            } else {
                console.log("Finished With All Async work!");
                resolve("Done with work!")
            }

        }

    });


}

3 个答案:

答案 0 :(得分:1)

使用eventEmitter似乎没有任何合理的理由,并且在下一行调用它时,只需使用Promise.all,而auxFunc.asyncFunc似乎返回了一个,你可能只需在地图中返回

function myFunc(objectToTest, testArray) {
    var promises = testArray.filter(function(item) {
        return objectToTest.name == item.name;
    }).map(function(itemInArray) {
        return auxFunc.asyncFunc(itemInArray);
    });

    Promise.all(promises).then(function(results) {
        console.log("Finished With All Async work!");
        // results would be all the results
    });
}

如果你必须等待每次调用,那么只是移动数组成员的递归函数似乎更容易

function myFunc(objectToTest, testArray) {
    return new Promise(function (resolve, reject) {
        var array = testArray.filter(function(item) {
            return objectToTest.name == item.name;
        });

        (function processArray(itemInArray) {
            auxFunc.asyncFunc(itemInArray).then(function (asyncResult) {
                if (array.length > 0) {
                    processArray(array.shift());
                } else {
                    resolve('all done');
                }
            });
        })(array.shift());
    });
}

答案 1 :(得分:1)

如果你想同时做多件事,

Promise.all非常有用。如果你想以线性方式做事,你可以将承诺链接起来。

所以我可以制作一个片段,我刚刚做了一个假装的async函数,sqr是它的值,然后我将它们全部添加到最后。

你也可以做更高级的版本,例如。 Bluebird Promises具有具有并发选项的map函数。

var somethings = [12,1,33,23,44,22,11,32,12,44,22,32];

function asyncSqr(v) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () { resolve(v*v); }, 200);
  });
}


function myFunc(a) {
  var sum = 0;
  return new Promise(function (resolve, reject) {
    function doNext() {
      var next = a.shift();    
      if (!next) return resolve(sum);
      console.log('sending: ' + next);
      return asyncSqr(next).then(function (r) { sum += r; doNext(); });
    }  
    doNext();    
  });
}

myFunc(somethings).then(function (r) {
  console.log('result: ' + r);
});

答案 2 :(得分:0)

EventEmmitters在这里似乎完全没必要。标准的承诺链将完成异步任务的排序。事实上,这是承诺链的主要 raison d'être(另一方面是错误处理)。

对于这项工作,模式的工作方式如下:

function myFunc(objectToTest, testArray) {
    // first, pre-filter testArray.
    var array = testArray.filter(function() {
        return objectToTest.name == item.name;
    });

    // now use .reduce() to build a promise chain from the filtered array.
    return array.reduce(function(chain, item) {
        return chain.then(function(previousResult) {
            return auxFunc.asyncFunc(item).then(function(result) {
                // Triggered when asyncFunc promise is resolved
                // ... do something with the result ...
                return result; // make this step's result available to next step in the chain (if required).
            });
        });
    }, Promise.resolve(intialValue));
}

进一步说明,过滤动作可以在减少时即时执行 - 无需预过滤。

function myFunc(objectToTest, testArray) {
    return testArray.reduce(function(chain, item) {
        if(objectToTest.name !== item.name) {
            // Filter on-the-fly
            // Don't extend the chain at this iteration of .reduce()
            return chain;
        } else {
            // item.name meets the criterion, so add an async task to the chain.
            return chain.then(function(previousResult) {
                return auxFunc.asyncFunc(item).then(function(result) {
                    // Triggered when asyncFunc promise is resolved
                    // ...
                    return result; // make result available to next step in the chain.
                });
            });
        }
    }, Promise.resolve(intialValue));
}