这一定很简单,但我无法理解。我有一个node.js应用程序,它使用请求库来获取许多URL。代码是这样的:
for(var i = 0; i < docs.length; i++){
var URL = docs[i].url;
request(URL, function(error, response, html){
console.log(URL);
//other code...
}
为简单起见,我们假设文档包含[url1,url2,url3 ...]等网址。通过第一次迭代,URL = url1并将请求发送到该URL。在第二次迭代中,请求被发送到url2,依此类推。但是,在循环结束时,URL = urln。在事件完成功能内部,当我记录URL时,我总是得到urln。但是,我需要能够获取[url1,url2,url3 ...]的相应网址。
任何想法,我如何维护URL的本地副本,当全局URL发生变化时保持不变的事件?
答案 0 :(得分:1)
基本上,您遇到的是JavaScript中的正常行为,并且没有Node.js的特殊行为。
JavaScript中唯一定义范围的是函数,函数可以访问自己的范围以及任何&#34;外部&#34;作用域。
因此,解决方案是将代码包装在一个函数中,该函数将全局变量作为参数并将其作为参数提供给函数中的代码:对于函数的每次调用都会对此进行求值,因此您的内部代码将获得自己的&#34; copy&#34;。
基本上你有两种选择。使用立即执行的函数表达式。这基本上只是一个无名称(即匿名)函数,在定义它的地方立即被调用:
for(var i = 0; i < docs.length; i++){
(function (url) {
request(url, function(error, response, html){
console.log(url);
});
})(doc.url);
}
或者使用数组的内置forEach
函数,该函数会自动将其主体包装在一个函数中(这会产生相同的效果):
docs.forEach(function (url) {
request(url, function(error, response, html){
console.log(url);
});
});
答案 1 :(得分:1)
您应该阅读javascript here
中的闭包同时,简单来说,i的值将在所有迭代结束时达到n。因此,你每次都会得到urln。如果将请求包装在一个立即调用的函数表达式中,那么您将在作用域链中创建另一个级别。通过这样做,请求方法的回调不会引用全局范围中的变量i,而是引用发送请求时函数范围内可用的变量i。你期待的那个价值。
代码就是这样的
for(var i = 0; i < docs.length; i++){
var URL = docs[i].url;
(function(currentURL) {
//now the URL is preserved as currentURL inside the scope of the function
request(currentURL, function(error, response, html){
console.log(currentURL);
//this value of currentURL is the one that was available in the scope chain
//other code...
});
})(URL);
}
答案 2 :(得分:0)
只需将代码包装在函数中或使用forEach。这是因为封闭范围。
docs.forEach(functiom(doc) {
var URL = doc.url;
request(URL, function(error, response, html){
console.log(URL);
//other code...
})
});
另一个修复
for(var i = 0; i < docs.length; i++){
makeRequest(docs[i]);
}
function makeRequest(doc) {
var URL = doc.url;
request(URL, function(error, response, html){
console.log(URL);
});
}
另一个更难以解决的问题是for循环中的闭包
for(var i = 0; i < docs.length; i++){
(function(doc) {
var URL = doc.url;
request(URL, function(error, response, html){
console.log(URL);
//other code...
});
})(docs[i]);
}
如果你使用像jshint这样的东西,它会警告你不要在for循环中创建函数,因为它会导致这样的问题。
答案 3 :(得分:0)
只需使用let
代替var
,即:
for(let i = 0; i < docs.length; i++){
let URL = docs[i].url;
request(URL, function(error, response, html){
console.log(URL);
//other code...
}