Aram_
Aram_

Reputation: 111

how to break for loop in promise?

var ing_data = savedata.ingredients.split(',');    
for(var i =0; i<ing_data.length; i++){

      var d = {
            content_name: ing_data[i],
            dogFoodId: dogId
      }
      db.dog_ingredients.create(d).then(function(data){

      }, function(e){
            console.log(e);

            res.status(403).send('Error');
            //break for loop this point

      });
    }

how to break for loop in promise?

I'm using node express, sequelize module

Upvotes: 2

Views: 2587

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074495

The loop will be over before the first then callback is triggered; this is one of the guarantees of promises (assuming that create operation returns a proper promise, not just a thenable; or at least that the thenable it returns completes asynchronously).

You can use the reduce trick to loop through adding those ingredients serially (one at a time); a promise rejection along the way will skip the remaining ingredients:

savedata.ingredients.split(',').reduce(function(p, ing) {
    // Chain this ingredient on the end of the promise, return
    // the new promise `then` returns, which gets passed to the
    // next iteration
    return p.then(function() {
        var d = {
            content_name: ing,
            dogFoodId: dogId
        };
        // Return the promise from `create`
        return db.dog_ingredients.create(d);
    });
}, Promise.resolve()/* Seeds the loop above */)
.catch(function(e) {
    // We got a rejection, which bypasses any pending resolution
    // handlers we set up above; process the rejection.
    console.log(e);
    res.status(403).send('Error');
    return Promise.reject(e); // Only need to propgate the rejection like this
                              // this if something will use the return value of
                              // this overall structure
});

That looks massive, but that's mostly comments and the object initializer; we could also write it like this (assuming we didn't need to propagate the rejection):

savedata.ingredients.split(',').reduce(function(p, ing) {
    return p.then(function() {
        return db.dog_ingredients.create({ content_name: ing, dogFoodId: dogId });
    });
}, Promise.resolve())
.catch(function(e) {
    res.status(403).send('Error');
});

(Or you can even get smaller, but for me debugging suffers — leave minifying to the minifier.)


I assume you don't want to add the ingredients in parallel since you've indicated you want to stop on the "first" error. But if you did, the code would be simpler:

Promise.all(savedata.ingredients.split(',').map(function(ing) {
    return db.dog_ingredients.create({ content_name: ing, dogFoodId: dogId });
}).catch(function(e) {
    res.status(403).send('Error');
    return Promise.reject(e);
});

(Assumes we don't need to propagate the rejection.)

Again, though, that's parallel.

Upvotes: 3

Related Questions