简体   繁体   中英

Scope of variable in anonymous function

I've got this function

function parseLink(link) {
    var product;
    request(link, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            var $ = cheerio.load(body);

            // title
            var title = $('h1').text();
            if (!title)
                var title = $('title').text();

            var description = $('meta[name="description"]').attr('content');

            product = new Product(link.trim(), title.trim(), description.trim());
        }
    });
    console.log(product);
    return product;
}

And I don't understand why when I do console.log(product) outside of the request call, I've got undefinded but inside, I can see my product.

I learn lot of things about scopes in javascript and I don't understand, causse I defined product in the top function. I need to return this variable for get it in another function, if do the return inside request I've got of course an undefined so I need to do that outside... Thank you

javascript does not run the code like c or php where you can be sure that the next line of code runs when the previous is ready. In your case request is an asynchronous function so the two lines

console.log(product);
return product;

are mostly run before your request function is ready. In that case you can not just return some value from your parseLink function. You have two possibilities here:

  1. use promises: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise

  2. use a callback:

like this:

function parseLink(link, callback) {
    var product;
    request(link, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            var $ = cheerio.load(body);

            // title
            var title = $('h1').text();
            if (!title)
                var title = $('title').text();

            var description = $('meta[name="description"]').attr('content');

            product = new Product(link.trim(), title.trim(), description.trim());
            callback(product);
        }
    });
}

and you run the code like

parseLink('http://...', function(product) { /* do something with the product */ });

ps: the use of callbacks is a lot easier imo, but in some cases you can to separate the scope for example if you run it in a for loop

request is an asynchronous call so this procedure gets pushed to the event queue which will run once the current call stack has finished. console.log prints undefined because that is the default value for unassigned variables.

You must use callbacks or promises if you need to return the value from the asynchronous call. Here's an example using a Promise :

function parseLink(link) {
  return new Promise((resolve, reject) => {
    request(link, function(error, response, body) {
      if (error) return reject(error);

      if (response.statusCode !== 200) {
        return reject(new Error('Not OK'));
      }

      var $ = cheerio.load(body);

      var title = $('h1').text() || $('title').text();
      var description = $('meta[name="description"]').attr('content');
      var product = new Product(link.trim(), title.trim(), description.trim());

      resolve(product);
    });
  });
}

parseLink('http://example.com')
  .then(product => {
    console.log(product);
  })
  .catch(error => {
    console.error(error);
  });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM