Xsmael Xsmael - 5 months ago 7
Node.js Question

how does Javascript(NodeJS) handle scope and context with regard to events

i'm a bit confused in a situaiton,

given the sample code here where i'm loading several urls, and connected the event Listener

var pages= Array();
var loading= Array();

for(i=0; i < urls.length; i++){
var page =new WebPage(urls[i]);

page.onLoadStarted = function() {
loading[i]= true;
console.log('Loading started');
};
pages[i]=page;

}


i have 5 urls, and i get 5 times "Loading started" in the console output, however the loading array had only one value defined (true) all the rest are "undefined";
Looks like when the event is triggered
loading[i]= true;
uses the last value of i to access the array instead of using its address. how can i fix that ?

I've tried adding a property to the page object, but same thing happens;

here is what i've tried:

var pages= Array();

for(i=0; i < urls.length; i++){
var page =new WebPage(urls[i]);

page.onLoadStarted = function() {
page.loading= true;
console.log('Loading started');
};
pages[i]=page;

}

Answer

If onLoadStarted is an event handler then the for loop is executed much faster than the all the event handlers. In that time i is 5 and during each function call, the sixth index of the array is populated with a true value. As the lower indices of array do no have any set value you get such output.

One option is using the Array.prototype.forEach or Array.prototype.map method. Both functions take a function as the handler. The handler which is a function, creates a new scope and remembers the defined values.

urls.forEach(function(url /* element */, i /* index */) {
   var page = new WebPage(url);

   page.onLoadStarted = function() {
       loading[i]= true;
       console.log('Loading started');
   };    
   pages[i]=page;
}) 
Comments