0

I have a producer-consumer design in javascript, where the producer is pulling some JSON data over ajax. The consumers each register interest in the data with a custom callback function, and then each gets a callback triggered after a slight delay when the data is available (or if the load fails).

My current function for actually triggering the callbacks looks like this:

// Function to iterate through all registered callbacks
this._processCallbacks = function() {
    var self = this;
    for (var callback of this.callbacks) {
        setTimeout(function(){ callback(self.data != null) }, 2000);
    }
}

... but with this the last callback in the list is called N times, rather than each callback being called once.

If I remove the setTimeout and just call synchronously it works fine ...

// Function to iterate through all registered callbacks
this._processCallbacks = function() {
    var self = this;
    for (var callback of this.callbacks) {
        callback(self.data != null);
    }
}

... so I assume I'm missing some subtlety of closure scope and timeouts. Any help appreciated - I'm not sure what I've missed (the only scope issue I was aware of was the issues around this being modified).

solidpixel
  • 10,688
  • 1
  • 20
  • 33
  • 1
    The timeouts are run asynchronously *after* the for loop has finished, so they use the value of `callback` as it is *after* the loop has finished. The `callback` and `self` variables are both defined within the same scope. – nnnnnn Aug 07 '16 at 12:13
  • Ah, got it - I assumed it would create a new copy of the closure for each iteration of the loop when the function for setTimeout was defined. – solidpixel Aug 07 '16 at 12:15
  • use `let` in this place instead of `var`: `for (let callback of this.callbacks) setTimeout(() => callback( this.data != null ), 2000);` – Thomas Aug 07 '16 at 12:26
  • @Isogen74, it does create a new copy of the closure for each iteration of the loop, but all of them reference the **same variable** (not the current value!); wich is updated on every iteration of the loop. – Thomas Aug 07 '16 at 12:29
  • Thanks for the clarification - unique closure, but with a reference binding back to the same variable. – solidpixel Aug 07 '16 at 12:41
  • @Thomas - Note that IE doesn't do `let` properly when it appears within the `for` like that (but `let` in the `for`'s body will work). – nnnnnn Aug 07 '16 at 13:04

0 Answers0