如何跳过" async.forEachOf" Node.js中的循环迭代

时间:2015-08-04 17:47:11

标签: javascript node.js asynchronous

async.waterfall嵌套在async.forEachOfLimit循环中,如下面的代码所示。

问题:当代码执行async.forEachLimit内的步骤时,如何跳过async.waterfall的迭代?换句话说,突破async.waterfall并返回async.forEachLimit。我已经在代码中评论了应该进行此项检查的位置

当前代码提供错误Callback was already called.

此外,如果我想要突破return callback()时使用cb()代替async.waterfall,则不会发生错误,但不会跳过此错误。

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')
})

错误

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.

所需输出

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

使用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')
})

输出

没有爆发......

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

1 个答案:

答案 0 :(得分:2)

在索引匹配1的第一个解决方案中,cb被调用两次,这就是导致Callback was already called错误的原因。虽然您调用forEachOfLimit回调cb,但您的代码不会停止执行并调用回调。在回调函数cb中再次执行。

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')
})

在第二个解决方案中,如果索引匹配1,则它调用不带参数的回调,并跳过使用null参数调用回调。仍然没有突破瀑布。

要使用瀑布解决您的问题,您有两种选择。

  1. 使用error参数调用瀑布的方法回调,该参数突破了瀑布而不是在瀑布的回调中处理此错误。

    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. 在每个waterfalled方法的开头跳过剩下的代码并立即调用回调(这是你在第二次尝试时所做的)

    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')
    })