How come a globally defined array that gets data pushed to it with in a callback function is empty in the global scope?

Problem

I assign an empty array to the global variable artistURLs. I then push strings (the local variable artistURL) into the artistURLs array with in the Cheerio .each() iterator method.

var request = require('request'),
  cheerio = require('cheerio'),
  url = 'http://www.primarytalent.com/',
  artistURLs = [];

request(url, function(err, resp, body){
  if(err)
    throw err;
  $ = cheerio.load(body);
  $('#rosterlists div li a').each(function(){
    var urlCap = this.attr('href').slice(1);
    var artistURL = url.concat(urlCap);
    artistURLs.push(artistURL);
  });
  console.log(artistURLs);
});

I know that artistURL is successfully being pushed into artistURLs because

console.log(artistURLs);

will display the populated array in my terminal. The problem is if I try running console.log(artistURLs); outside of the callback function in the global scope. For example

var request = require('request'),
  cheerio = require('cheerio'),
  url = 'http://www.primarytalent.com/',
  artistURLs = [];

request(url, function(err, resp, body){
  if(err)
    throw err;
  $ = cheerio.load(body);
  $('#rosterlists div li a').each(function(){
    var urlCap = this.attr('href').slice(1);
    var artistURL = url.concat(urlCap);
    artistURLs.push(artistURL);
  });
});

console.log(artistURLs);

So you can see that I have moved console.log(artistURLs); outside of request(). For some reason trying to access artistURLs in the global scope returns me an empty array as if all the processing that happened with in `request()~ never even happened.

How come this is happening and how can ensure that all the urls that are being pushed into artistURLs remain in artistURLs?

Thanks

Problem courtesy of: s3z

Solution

The request() module is asynchronous, so console.log() is executing before the HTTP call completes when you use console.log(). For example, take this code:

var request = require('request');
var cheerio = require('cheerio');
var url = 'http://www.primarytalent.com/';
var artistURLs = [];

request(url, function(err, resp, body){
  if (err)
    throw err;
  $ = cheerio.load(body);
  $('#rosterlists div li a').each(function(){
    var urlCap = this.attr('href').slice(1);
    var artistURL = url.concat(urlCap);
    artistURLs.push(artistURL);
    console.log('push');
  });
});

console.log(artistURLs);

You will see this result:

[]
push
push
...
push
push
push

To prevent this from happening, only use the variable artistURLs inside of the HTTP request callback.

Solution courtesy of: hexacyanide

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.