Frage

While working on nodejs programming, I found a simple, but interesting problem.
To execute a bundle of asynchronous functions in turns, I usually use 'job list array' with async.series.

By following steps :

1. Define an array
2. Push job functions into array.
3. Using async.series, execute it sequentially.
e.g. async.series(jobFunctionList, callback);

Following example code is simplified one.
Described in comment, it doesn't work as I expected.

The variable 'key' and 'value' changes
even after Job function is defined and pushed into jobList array.

It seems that pushed function references external variable constantly,
not a value of created circumstance.


I found a solution to resolve this problem, but don't know why it works as that.

var dataList = { key1: 'value1', key2: 'value2' };

var jobList = new Array();

for (var key in dataList)
{
    var value = dataList[key];

    jobList.push(
        function (next)
        {
            console.log(key + ' : ' + value);
        }
    );
}

(jobList[0])();
(jobList[1])();

/* Expected Output :

key1 : value1
key2 : value2

*/

/* Real Output :

key2 : value2  <--- WHY ???
key2 : value2

*/
War es hilfreich?

Lösung

The anonymous functions use(share) the same key and value variables from the outer scope. When the for is over, the values they use are key2 value2, not the values they had when the functions were defined.

for (var key in dataList) // definition of key
{
    var value = dataList[key]; // definition of value

    jobList.push(
        function (next)
        {
            console.log(key + ' : ' + value); // uses key and value from the outer scope
        }
    );
}

(jobList[0])(); // key and value are key2 value2 after for, so they are printed
(jobList[1])(); // same

The solution is to create a closure in which key and value are local:

for (var key in dataList) // definition of key
{
    var value = dataList[key]; // definition of value

    jobList.push(
      function(k,v){ // k,v local copies of key and value
        return function (next)
          {
            console.log(k + ' : ' + v); // uses local copies, created one for each iteration
          }
      }(key,value); // immediately execute the outer anonymous function, it just creates a local scope
    );
}

Andere Tipps

As Teemu stated, its because by the time that the for loop finished, the value has already changed

What you need to do is the following:

var dataList = { key1: 'value1', key2: 'value2' };

var jobList = new Array();

for (var key in dataList)
{
    var value = dataList[key];

    jobList.push(
        (function(savedKey, savedValue) {
            return function (next) {
                console.log(savedKey + ' : ' + savedValue);
            }
        })(key, value)
    );
}

(jobList[0])();
(jobList[1])();

Although savedKey and savedValue can be called key and value and it will refer to the new one, which may make more sense reading it

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top