Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.JS: How to pass variables to asynchronous callbacks? [duplicate]

I'm sure my problem is based on a lack of understanding of asynch programming in node.js but here goes.

For example: I have a list of links I want to crawl. When each asynch request returns I want to know which URL it is for. But, presumably because of race conditions, each request returns with the URL set to the last value in the list.

var links = ['http://google.com', 'http://yahoo.com']; for (link in links) {     var url = links[link];     require('request')(url, function() {         console.log(url);     }); } 

Expected output:

http://google.com http://yahoo.com 

Actual output:

http://yahoo.com http://yahoo.com 

So my question is either:

  1. How do I pass url (by value) to the call back function? OR
  2. What is the proper way of chaining the HTTP requests so they run sequentially? OR
  3. Something else I'm missing?

PS: For 1. I don't want a solution which examines the callback's parameters but a general way of a callback knowing about variables 'from above'.

like image 560
Marc Avatar asked Nov 04 '12 18:11

Marc


People also ask

Can callbacks be asynchronous?

Callbacks are not asynchronous by nature, but can be used for asynchronous purposes. In this code, you define a function fn , define a function higherOrderFunction that takes a function callback as an argument, and pass fn as a callback to higherOrderFunction .

Can callbacks be synchronous?

The callback is a function that's accepted as an argument and executed by another function (the higher-order function). There are 2 kinds of callback functions: synchronous and asynchronous. The synchronous callbacks are executed at the same time as the higher-order function that uses the callback.

Which is faster callbacks or promises?

So from my findings i assure you ES6 promises are faster and recommended than old callbacks.


1 Answers

Your url variable is not scoped to the for loop as JavaScript only supports global and function scoping. So you need to create a function scope for your request call to capture the url value in each iteration of the loop by using an immediate function:

var links = ['http://google.com', 'http://yahoo.com']; for (link in links) {     (function(url) {         require('request')(url, function() {             console.log(url);         });     })(links[link]); } 

BTW, embedding a require in the middle of loop isn't good practice. It should probably be re-written as:

var request = require('request'); var links = ['http://google.com', 'http://yahoo.com']; for (link in links) {     (function(url) {         request(url, function() {             console.log(url);         });     })(links[link]); } 
like image 104
JohnnyHK Avatar answered Sep 29 '22 18:09

JohnnyHK