0

I hope this question is not a duplicate, I have searched similar question here but got no matching result.

In node.js Below code is polluting the storage variable. And I really can't figure out why.

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 ]

However if I don't use _.after() it will give the expected result. Using underscore or lodash give same result.

Below code is working fine.

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 ]

How should i identify the root cause !

1 Answer 1

2

The magic of javascript's context. When you are doing:

returnStorage = _.after(l, doCallback);

returnStorage is the same for your second call of add.

You need to declare it with var to make it new and local to the function.

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 ]

Bit of explanation:

On your first call of add(), returnStorage is undefined. It will then be defined it the global context since their is no var before it.

On your second call, the variable is declared, and when you set it, you also set it for the first add() call. So after the 10ms each elements of [1,2,3] have called returnStorage (the second one) and the next element of [4,5,6,7] will trigger the returnStorage callback, any further calls will also triggers it.

Sign up to request clarification or add additional context in comments.

1 Comment

You're right. From now on, I will put 'use strict' to all my modules, to avoid this mistake on the future.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.