80

Let's say I have something as follows:

for(var i = 0; i < length; i++){
  var variable = variables[i];
  otherVariable.doSomething(variable, function(err){ //callback for when doSomething ends
    do something else with variable;
  }

By the time the callbacks are called, variable will inevitably be the last variable for all the callbacks, instead of being a different one for each callback, as I would like. I realize that I could pass variable to doSomething() and then get that passed back as part of the callback, but doSomething() is part of an external library, and I'd rather not mess around with the source code for that.

Do those of you that know JavaScript better than I do know if there are any alternative ways to do what I'd like to do?

Best, and thanks,
Sami

1
  • Don't know much about JS, but it seems that you can now use let: let i = 0; i < length; ++i Commented May 19, 2020 at 15:21

2 Answers 2

56

A common, if ugly, way of dealing with this situation is to use another function that is immediately invoked to create a scope to hold the variable.

for(var i = 0; i < length; i++) {
  var variable = variables[i];
  otherVariable.doSomething(function(v) { return function(err) { /* something with v */ }; }(variable));
}

Notice that inside the immediately invoked function the callback that is being created, and returned, references the parameter to the function v and not the outside variable. To make this read much better I would suggest extracting the constructor of the callback as a named function.

function callbackFor(v) {
  return function(err) { /* something with v */ };
}
for(var i = 0; i < length; i++) {
  var variable = variables[i];
  otherVariable.doSomething(callbackFor(variable));
}
Sign up to request clarification or add additional context in comments.

3 Comments

Unfortunately, this doesn't help in my case because doSomething() is a function from a library that I don't want to edit. As this library gets updated, I'll have to keep reediting the source code and that's something that I just don't want to deal with. Assuming I cannot alter the function doSomething(), is there anything I can do?
This doesn't require any change to doSomething(). I assumed that doSomething simply took a callback and that the inclusion of the variable parameter was something that you might be proposing to change. If the signature of doSomething is doSomething(val, callback) then just modify my example to otherVariable.doSomething(variable, callbackFor(variable)). The important thing is that a new scope is created, by calling a function, to hold onto the value of variable for the callback function.
Hmm so I guess I'm a little confused. The way doSomething() works is that it's passed the variable, and then eventually doSomething() will call the callback function specified, where the first parameter is any potential error code that resulted from doSomething(). If I put a function(variable) wrapper around the callback to create a new scope, wouldn't that function(variable) become the callback instead, and the parameter variable actually be the error message?
42

Ok I've seemed to figure this out. What I needed to do was to put a function(var) wrapper around otherVariable.doSomething(), so the updated code looks as follows:

for(var i = 0; i < length; i++){
  var variable = variables[i];
  (function(var){ //start wrapper code
    otherVariable.doSomething(var, function(err){ //callback for when doSomething ends
      do something else with var; //please note that i'm dealing with var here, not variable
    }
  })(variable);//passing in variable to var here
}

hope this helps anybody else that gets stuck on something like this in the future!

@aparker42, i'd still love to hear your answer to my question in the comment to your question, since that still does confuse me.

EDIT: of course, since this is javascript, you wouldn't want to use var as a variable name.

4 Comments

Yes, this is essentially the same thing as what my answer had. The difference is that you use the immediately invoked function to create a scope in which you do the call to doSomething. My answer just created the callback in that scope and then returned it. In the end they both achieve the same thing.
To support and clarify, yes, this is the same answer that aparker42 put, just in a different format. The callback in that case is not being CALLED by doSomething, it's immediately returning a value.
Maybe not such a good idea to have an identifier named var in JavaScript.
Great work around, saved my code.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.