Reputation: 25830
I'm calling sendMessage in a loop for a bunch of appIds that are in an array. When my callback is called, I need to check for an error and then "blacklist" the appId that has the error. The problem is that every way I've tried this causes the appId in the callback to be changed by the time it's called! So the wrong appId gets blacklisted.
I have three versions I tried (see below). One never blacklists, and the other two do the wrong one:
** THIS ONE BLACK LISTS THE WRONG ONE **
for ( var appName in apps )
{
var app = apps[ appName ];
var appId = app[ "appId" ];
//Send message to that app
chrome.runtime.sendMessage(
app[ "appId" ],
app,
function (response)
{
var lastError = chrome.runtime.lastError;
//Want to blacklist apps here
if ( lastError && lastError.message.indexOf( "not exist" ) !== -1 )
{
//This blacklists the wrong one!
myGlobalObject.addToTimeout( appId );
}
}
);
}
** THIS ONE ALSO BLACK LISTS THE WRONG ONE **
for ( var appName in apps )
{
var app = apps[ appName ];
var appId = app[ "appId" ];
//Send message to that app
chrome.runtime.sendMessage(
app[ "appId" ],
app,
function (response)
{
var lastError = chrome.runtime.lastError;
//Want to blacklist apps here
if ( lastError && lastError.message.indexOf( "not exist" ) !== -1 )
{
//This blacklists the wrong one!
myGlobalObject.addToTimeout( this[ "appId" ] );
}
}.bind( app )
);
}
** THIS ONE NEVER BLACK LISTS IT **
for ( var appName in apps )
{
var app = apps[ appName ];
//Send message to that app
chrome.runtime.sendMessage(
app[ "appId" ],
app,
function (response)
{
var lastError = chrome.runtime.lastError;
//Want to blacklist apps here
if ( lastError && lastError.message.indexOf( "not exist" ) !== -1 )
{
//Somehow this NEVER blacklists it!
myGlobalObject.addToTimeout( app[ "appId" ] );
}
}
);
}
Upvotes: 0
Views: 188
Reputation: 707436
For callbacks that are called some time later, you need to "freeze" the value of the variable in a closure. There are several ways to do so, here's one using an immediate invoking function which passes the variables as arguments and they get captured in that function closure so their value remains what you want for the duration of the callback:
for ( var appName in apps )
{
var app = apps[ appName ];
var appId = app[ "appId" ];
// this creates a closure which captures the values of your variables
// and holds them at the desired value until the callback is called
// a separate and unique closure will be created
// for each cycle of the for loop
(function(appID) {
//Send message to that app
chrome.runtime.sendMessage(
appId,
app,
function (response)
{
// since this is called some time later
// variables outside this may have different values
// as the outer for loop continued to run
var lastError = chrome.runtime.lastError;
//Want to blacklist apps here
if ( lastError && lastError.message.indexOf( "not exist" ) !== -1 )
{
//This blacklists the wrong one!
myGlobalObject.addToTimeout( appId );
}
}
);
})(appID);
}
Upvotes: 3