在异步回调中使用 _.after(),污染数组变量

Using _.after() in async callback, polluting array variable

我希望这个问题不是重复的,我在这里搜索过类似的问题但没有找到匹配的结果。

In node.js 下面的代码污染了 storage 变量。我真的想不通为什么。

var _ = require('underscore'); // same result by using lodash

function add(arr, callback) {
    var l = arr.length,
        storage = [];

    function doCallback() {
        callback(storage);
    }

    returnStorage = _.after(l, doCallback);
    _.each(arr, function (a) {
        _.delay(function () {
            storage.push(a);
            returnStorage();
        }, 10);
    });
}

function callbackHandler(result) {
    console.log(result);
}

add([1,2,3], callbackHandler),
add([4,5,6,7], callbackHandler);

// in console will print wrong result:
// [ 4 ]
// [ 4, 5 ]
// [ 4, 5, 6 ]
// [ 4, 5, 6, 7 ]

但是,如果我不使用 _.after(),它将给出预期的结果。使用 underscorelodash 得到相同的结果。

下面的代码工作正常。

var _ = require('underscore'); // same result by using lodash

function add(arr, callback) {
    var l = arr.length,
        storage = [];

    function returnStorage() {
        if (storage.length == l) {
            callback(storage);
        }
    }

    _.each(arr, function (a) {
        _.delay(function () {
            storage.push(a);
            returnStorage();
        }, 10);
    });
}

function callbackHandler(result) {
    console.log(result);
}

add([1,2,3], callbackHandler),
add([4,5,6,7], callbackHandler);

// in console will print correct result:
// [ 1, 2, 3 ]
// [ 4, 5, 6, 7 ]

我应该如何确定根本原因!

javascript 上下文的魔力。当你在做的时候:

returnStorage = _.after(l, doCallback);

returnStorage 与您第二次调用 add 相同。

您需要用 var 声明它,使其成为函数的新函数和本地函数。

var _ = require('underscore'); // same result by using lodash

function add(arr, callback) {
    var l = arr.length,
        storage = [];

    function doCallback() {
        callback(storage);
    }

    var returnStorage = _.after(l, doCallback);
    _.each(arr, function (a) {
        _.delay(function () {
            storage.push(a);
            returnStorage();
        }, 10);
    });
}

function callbackHandler(result) {
    console.log(result);
}

add([1,2,3], callbackHandler),
add([4,5,6,7], callbackHandler);

// in console:
// [ 1, 2, 3 ]
// [ 4, 5, 6, 7 ]

一点解释:

在您第一次调用 add() 时,returnStorageundefined。然后它将被定义为全局上下文,因为它们之前没有 var

在第二次调用时,变量被声明,当您设置它时,您也为第一次 add() 调用设置了它。因此,在 [1,2,3] 的每个元素调用 returnStorage(第二个)10 毫秒后,[4,5,6,7] 的下一个元素将触发 returnStorage 回调,任何进一步的调用也将触发它。