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

How to resolve a promise from the outside with eventEmitter in nodeJS?

首先让我说一下,我是 Node 的新手,可能犯了设计错误,但我想不出更好的方法来做我想做的事。

我有一个函数需要遍历一个数组,并且它需要为数组中的每个元素做一些异步工作。

我不希望函数的调用者在处理完数组中的所有元素之前继续执行,因此我将我的函数包装在 Promise 中,该 Promise 仅在所有元素的工作完成时才解析。

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

当所有元素都被处理后 array.length==0 承诺被解决。

我遇到的问题是我的事件侦听器在函数内部,并且每次函数 运行 时都会创建。另一方面,我不能将它放在函数之外,因为那样我就无法为我的函数解析 promise。

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

我在创建侦听器时尝试使用 .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!")
            }

        }

    });


}

似乎没有任何充分的理由使用 eventEmitter 并在下一行调用它,只需使用 Promise.all 代替,并且 auxFunc.asyncFunc 似乎 return一个thenable,你可能只是return它在地图

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());
    });
}

Promise.all,如果你想同时做多件事,这非常有用。如果你想以线性方式做事,你可以链接承诺。

所以我可以做一个片段,我刚刚做了一个假设的异步函数,它的值为 sqr,然后我在最后把它们全部加起来。

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

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);
});

EventEmmitter 在这里似乎完全没有必要。标准的承诺链将完成异步任务的排序工作。事实上,这是承诺链的主要存在理由(另一方面是错误处理)。

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

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));
}