【问题标题】:Unexpected behaviour of NodeJS arrayNodeJS 数组的意外行为
【发布时间】:2016-11-08 00:18:30
【问题描述】:

我目前正在学习如何使用 NodeJS,并编写了这个相对简单的函数来以固定的时间间隔运行。此函数的目的是检索新创建的 Droplet 并更新其 IP 地址。

router.newDroplets = setInterval(function() {

    Server.find().then(function(svrs) {
        for (var i = 0; i < svrs.length; i++) {
            if (svrs[i].status == "Creating") {
                library.getDropletById(svrs[i].serverid).then(function(svr) {
                    if (svr.droplet) {
                        for (var j = 0; j < svr.droplet.networks.v4.length; j++) {
                            if(svr.droplet.networks.v4[j].type == 'public') {
                                var ip_address = svr.droplet.networks.v4[j].ip_address;
                                console.log(ip_address);

                                Server.update({serverid: svr.droplet.id}, {ipaddress: ip_address, status: "Online"}, function(error, n) {
                                    if (error) console.log(error);
                                    else console.log(n);
                                });
                            }
                        }
                    } else if (svr.id) {
                        // NOTE THIS LINE
                        console.log(svrs);
                    }

                }, function() {

                });
            }
        }
    }, function() {

    });

}, 2500);

奇怪的行为是上面标记的行。

当我使用console.log(svrs) 时,我会在我的 MongoDB 的服务器集合中获得一组 JSON 文档。但是,当我使用console.log(svrs[i]) 时,控制台中会记录undefined。即使我在 for 循环之外声明 var i = 0; 也会发生这种情况。为什么会发生这种情况?如何访问svrs[i]

【问题讨论】:

  • This happens even if I declare var i = 0; outside the for loop,哪个for循环?
  • 正确使用promise,避免编写这样的意大利面条式代码(嵌套promise)。
  • 您是否尝试登录i
  • @AlexeyTen 我尝试记录 i 并收到 5,这是我的服务器集合中的文档数。
  • 我通常使用 bluebird 库。它有很好的文档,可以是相关的。请查看bluebirdjs.com/docs/anti-patterns.html

标签: javascript arrays node.js mongodb mongoose


【解决方案1】:

Promise 的工作方式是 Promise 链异步运行。到代码运行时,i 等于svrs.length,所以svrs[i] 将是undefined。这是因为 for 循环在调用任何 then 回调之前完整执行。您可以将您的代码转换为使用Array.prototype.forEach

所以你可以尝试类似的东西

svrs.forEach(function(svrInstance, i) {
  if (svrInstance.status == "Creating") {
    library.getDropletById(svrInstance.serverid).then(function(svr) {
      if (svr.droplet) {
        ...
      } else if (svr.id) {
        console.log(svrs[i]);
      }
     });
   }
});

【讨论】:

  • 非常感谢您的解释和建议。我从来不知道then 回调只有在for 循环完成循环后才会被调用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 2010-12-03
  • 1970-01-01
相关资源
最近更新 更多