问题
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:
- How do I pass url (by value) to the call back function? OR
- What is the proper way of chaining the HTTP requests so they run sequentially? OR
- 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'.
回答1:
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]);
}
回答2:
Check this blog out. A variable can be passed by using .bind() method. In your case it would be like this:
var links = ['http://google.com', 'http://yahoo.com'];
for (link in links) {
var url = links[link];
require('request')(url, function() {
console.log(this.urlAsy);
}.bind({urlAsy:url}));
}
回答3:
See https://stackoverflow.com/a/11747331/243639 for a general discussion of this issue.
I'd suggest something like
var links = ['http://google.com', 'http://yahoo.com'];
function createCallback(_url) {
return function() {
console.log(_url);
}
};
for (link in links) {
var url = links[link];
require('request')(url, createCallback(url));
}
来源:https://stackoverflow.com/questions/13221769/node-js-how-to-pass-variables-to-asynchronous-callbacks