Reputation: 63687
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
Upvotes: 0
Views: 3903
Reputation: 1748
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.
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')
});
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')
})
Upvotes: 2