Как разрешить обещание извне с eventEmitter в nodeJS?

Позвольте мне начать с того, что я очень новичок в Node и, возможно, сделал ошибку дизайна, но я не мог найти лучшего способа делать то, что хочу.

У меня есть функция, которая требует итерации по массиву, и для каждого элемента массива необходимо выполнить некоторую работу async.

Я не хочу, чтобы вызывающая функция выполнялась до тех пор, пока все элементы массива не обработаны, поэтому я завернул свою функцию в 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!")
            }

        }

    });


}

javascript,node.js,promise,eventemitter,

0

Ответов: 3


1 принят

var somethings = [ 12 , 1 , 33 , 23 , 44 , 22 , 11 , 32 , 12 , 44 , 22 , 32 ]; function asyncSqr ( v ) { return new Promise ( функция ( разрешение , отклонение ) { setTimeout ( function () { resolve ( v * v ); }, 200 ); }); } function myFunc ( a ) { var sum = 0 ; Возврат нового обещания ( функция ( разрешение , отклонение ) { function doNext () { var next = a . shift (); if (! next ) return resolve ( sum ); console . log ( ' send :' + next ); return asyncSqr ( далее ), затем ( function ( r ) { sum + = r ; doNext (); }); } doNext (); }); } myFunc ( somethings ). затем ( function ( r ) { console . log ( 'result:' + r ); }); , очень полезно, если вы хотите делать несколько вещей одновременно. Если вы хотите делать что-то линейным способом, вы можете связать обещания.

Таким образом, я мог бы сделать фрагмент, я только что сделал вид асинхронной функции, что значение sqr это значение, а затем я добавляю их все в конце.

Вы можете сделать более продвинутую версию, например. У Bluebird Promises есть функция карты, у которой есть опция параллелизма.

Promise.all


1

Кажется, нет никакой веской причины использовать eventEmitter, а в следующей строке вызывать его, просто используйте Promise.allвместо этого, и, как auxFunc.asyncFuncкажется, возвращает thenable, вы, вероятно, можете просто вернуть его на карте

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

0

EventEmmitters здесь совершенно не нужны. Стандартная цепочка обещаний будет выполнять задание асинхронных задач. На самом деле это основной смысл цепи обещаний (другим аспектом является обработка ошибок).

Для этой работы шаблон работает следующим образом:

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));
}
JavaScript, Node.js, обещание, EventEmitter,
Похожие вопросы