Node.js在本地范围内保留全局变量的副本

时间:2015-03-21 17:19:35

标签: node.js node-request

这一定很简单,但我无法理解。我有一个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发生变化时保持不变的事件?

4 个答案:

答案 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...
}