简体   繁体   中英

How to Skip a “async.forEachOf” loop iteration in Node.js

A async.waterfall is nested within a async.forEachOfLimit loop as shown in the code below.

Question: How do you skip an iteration of async.forEachLimit when the code is executing a step inside async.waterfall ? In other words, break out of async.waterfall and back into async.forEachLimit . I have commented the location in the code where this check should occur

The current code gives an error Callback was already called.

Also, if i use a return callback() in place of cb() when I want to break out of async.waterfall , no error occurs but it is not skipped.

var async = require('async')
var users = ['a','b','c']

async.forEachOfLimit(users, 1, function(user, index, cb) {

    console.log(index + ': ' + user)

    async.waterfall([
        function(callback) {
            callback(null);
        },
        function(callback) {
            // Skip async.forEAchOfLimit iteration when index == 1
            if(index == 1)
                cb()

            callback(null);
        }
    ], function (err, result) {
        console.log(index + ": done")
        cb()
    });

}, function() {
    console.log('ALL done')
})

Error

0: a
0: done
1: b
2: c
1: done

/Users/x/test/node_modules/async/lib/async.js:43
            if (fn === null) throw new Error("Callback was already called.");
                                   ^
Error: Callback was already called.

Desired Output

0: a
0: done
1: b
2: c
2: done
ALL done

Using return callback()

var async = require('async')
var users = ['a','b','c']

async.forEachOfLimit(users, 1, function(user, index, cb) {

    console.log(index + ': ' + user)

    async.waterfall([
        function(callback) {
            callback(null);
        },
        function(callback) {
            // Skip async.forEAchOfLimit iteration when index == 1
            if(index == 1)
                return callback()

            callback(null);
        }
    ], function (err, result) {
        console.log(index + ": done")
        cb()
    });

}, function() {
    console.log('ALL done')
})

Output

Doesn't break out...

0: a
0: done
1: b
1: done
2: c
2: done
ALL done

In your first solution when index matches 1, cb is called twice, that is why you keep getting Callback was already called error. Although you call forEachOfLimit callback cb , your code doesn't stop execution and calls callback. In callback function cb is executed one more time.

var async = require('async')
var users = ['a','b','c']

async.forEachOfLimit(users, 1, function(user, index, cb) {

    console.log(index + ': ' + user)

    async.waterfall([
        function(callback) {
            callback(null);
        },
        function(callback) {
            // Skip async.forEAchOfLimit iteration when index == 1
            if(index == 1)
                cb() // First callback call

            callback(null);
        }
    ], function (err, result) {
        console.log(index + ": done")
        cb() // Second callback call
    });

}, function() {
    console.log('ALL done')
})

In second solution if index matches 1, it calls callback with no arguments and skips calling callback with null argument. Still doesn't break out of waterfall.

To solve your problem using waterfall you have two options.

  1. Call waterfall's method callback with an error argument, which breaks out of waterfall and than handle this error in waterfall's callback.

     var async = require('async') var users = ['a','b','c'] async.forEachOfLimit(users, 1, function(user, index, cb) { console.log(index + ': ' + user) async.waterfall([ function(callback) { callback(null); }, function(callback) { // Skip async.forEAchOfLimit iteration when index == 1 if(index == 1) return callback(new Error('Index equals 1')); callback(null); } ], function (err, result) { console.log(index + ": done") if(err.message == 'Index equals 1') { err = null; // If you want to continue executing forEachOfLimit no error must be passed to cb } cb(err, result); }); }, function() { console.log('ALL done') }); 
  2. In the beginning of each waterfalled method skip the rest of the code and call callback immediately (which is what you've done in second attempt)

     var async = require('async') var users = ['a','b','c'] async.forEachOfLimit(users, 1, function(user, index, cb) { console.log(index + ': ' + user) async.waterfall([ function(callback) { callback(null); }, function(callback) { // Skip execution of the rest of waterfall method immediately if(index == 1) return callback() // Some additional code here callback(null); } ], function (err, result) { console.log(index + ": done") cb() }); }, function() { console.log('ALL done') }) 

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