Reputation: 3
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 !
Upvotes: 0
Views: 220
Reputation: 6478
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 ]
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.
Upvotes: 2