简体   繁体   中英

Wait On For Loop In Node Promise

I'm trying to run a sequence of promises using the Q library.

The merge notes function creates a new note in the database and I have to run the functions in order due to some unique constraints.

The promises are running in sequence no problem, but I need to push all of the newNotes into an array in workNotes and then resolve that array.

Everything I have tried resolves the promise before the chain is over.

To clarify the problem, I need to resolve notesList after the chain has completed and every resulting newNote has been pushed to notesList.

workNotes(notes){
    var _this = this;
    var notesList = [];
    return new Promise(
        function(resolve,reject){
            var chain = Q.when();
            notes.forEach(function(note){
                chain = chain.then(function(newNote){
                   _this.notesList.push(newNote);
                   return _this.mergeNotes(note);
                 });
             });
            resolve(notesList)
        }          
    );
}


mergeNotes(notes){
    return new Promise(
        function(resolve,reject){
            doSomething(note)
            .then(function(newNote){
             resolve(newNote);
            })   
         }       
    );
}

Change mergeNotes() to return the new promise:

mergeNotes(notes){
    return doSomething(note);
}

You were returning a promise, but it was not connected in any way to the doSomething() promise and thus it didn't wait for that.

Avoid the promise anti-pattern of wrapping an existing promise in a newly created promise. Instead, just return the promise you already have.

I'd change the rest of your code to this:

workNotes(notes) {
    let allNotes = [];
    return notes.reduce(function(p, note) {
        return p.then(function() {
            return mergeNotes(note);
        }).then(function(newNote) {
            allNotes.push(newNote);
        });
    }, Promise.resolve()).then(function() {
        return allNotes;
    });
}

With the Bluebird promise library, you could take advantage of Promise.mapSeries() which processes an array in sequence and returns a resolved array which is exactly what you need:

workNotes(notes) {
    return Promise.mapSeries(notes, function(note) {
        return mergeNotes(note);
    });
}

The resolved value of the promise returned by workNotes() will be an array of notes.

Drop the useless _this. (notice that this is not about scope!), avoid the Promise constructor antipattern , swap the order of calls to push and mergeNotes , and use reduce instead of forEach to fold an array to a single value:

function workNotes(notes) {
    var notesList = [];
    return notes.reduce(function(chain, note) {
        return chain.then(function() {
            return mergeNotes(note);
        }).then(function(newNote){
            notesList.push(newNote);
        });
    }, Q.when()).then(function() {
        return notesList;
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM