-1

我有一个 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...
}

为简单起见,假设docs包含 [URL1, URL2, URL3, ...] 之类的 URL。在第一次迭代中,URL = URL1 并且请求被发送到该 URL。在第二次迭代中,向 URL2 发送一个请求,依此类推。但是,在循环结束时,URL = URLn。在事件完成函数中,当我记录 URL 时,我总是得到 URLn。但是,我需要能够获取 [URL1, URL2, URL3, ...] 的相应 URL。

任何想法,我如何维护 URL 的本地副本,当全局 URL 发生更改时该事件保持不变?

这一定很容易,但我无法弄清楚。

4

4 回答 4

1

基本上,您所体验的是 JavaScript 中的正常行为,而不是 Node.js 的特殊行为。

JavaScript 中唯一定义作用域的是函数,函数可以访问它们自己的作用域以及任何“外部”作用域。

因此,解决方案是将您的代码包装在一个函数中,该函数将全局变量作为参数并将其作为参数提供给函数内的代码:这个函数会针对函数的每次调用进行评估,因此您的内部代码将得到它自己的“副本”。

基本上你有两个选择。要么使用立即执行的函数表达式。这基本上只是一个无名(即匿名)函数,在定义它的地方立即调用:

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); 
  });
});
于 2015-03-21T17:27:53.070 回答
1

您应该在此处阅读 JavaScript 中的闭包。

同时,简单来说, 的值in在所有迭代结束时达到。因此,您每次都会得到 URLn。如果您将请求包装在立即调用的函数表达式中,您将在作用域链中创建另一个级别。通过这样做,请求方法的回调将不会引用i全局范围内的变量,而是引用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);
}
于 2015-03-21T17:28:26.253 回答
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循环中创建函数,因为它会导致这样的问题。

于 2015-03-21T17:23:11.433 回答
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...
}
于 2016-05-21T06:05:25.143 回答