Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asynchronous Javascript Variable Overwrite

Tags:

javascript

The code has an issue that the variable gets over written when the asynchronous function is called. How can it be fixed?

Code:

for (x in files) {

 asynchronousFunction(var1, var2, function(){
      console.log(x.someVaraible);
  }); 

}

Now the issue is that when the callback function in the asynchronousFunction is called the x.files variable has been updated to the next varaible in the json array files. I want that the variable should contain the previous value.

The number of variables in the callback function can not be changes, so variable name can not be sent in the call back function.

like image 696
S. A. Malik Avatar asked Jul 31 '12 19:07

S. A. Malik


2 Answers

The problem with using 'local' variables in javascript is that your variables actually have function scope, rather than block scope - like Java and C# etc has.

One way to get around this is using let which has block scope, but only firefox supports this currently.

So this code would work in firefox only:

for (var x in files) {
  // This variable has BLOCK scope
  let file = files[x];
  asynchronousFunction(var1, var2, function(){
     console.log(file.someVariable);
  }); 
}

For other browsers, the alternative is to use closures

for (var x in files) {
  var file = files[x];
  asynchronousFunction(var1, var2, (function(file){
      return function() {
                console.log(file.someVariable);
             };
  })(file); 
}

Another way you could do this is using map/forEach, assuming that the datatype of files is an array.

files.forEach(function(file) {
     asynchronousFunction(var1, var2, function(){
                console.log(file.someVariable);
             });
});

If it's not an array, then you can always use this technique

 [].forEach.call(files, function(file) {
     asynchronousFunction(var1, var2, function(){
                console.log(file.someVariable);
             });
});

The fuller way of writing this is of course

Array.prototype.forEach.call(files, function(file) {
     // As before

But I feel [].forEach is nicer on the eyes.

like image 133
AlanFoster Avatar answered Sep 21 '22 19:09

AlanFoster


You need to disentangle the x from the closure created by the callback function. Short answer:

for (x in files) {
    asynchronousFunction(var1, var2,
        (function(y){
            return function(){
                console.log(y.someVaraible);
            }
        })(x)
    ); 
}

For a longer answer and explanation see my answer to a previous question: Please explain the use of JavaScript closures in loops

like image 25
slebetman Avatar answered Sep 24 '22 19:09

slebetman