node.js - 异步 Node.js 循环中的变量作用域

标签 node.js asynchronous promise sails.js q

我正在尝试在数组上运行一些数据库查询(使用 sails.js),并在查询返回时执行某些操作。我认为最好的方法是使用 for 循环并异步解决 promise ,一旦全部解决,就继续。但是,只有数组中的最后一个 promise 正在解析,并且它会解析多次,因为在每个“User.findOne...”then 函数中,索引是 array.length-1。

我的问题:

  1. 异步循环中的变量作用域如何工作?解释这一点的最佳资源?
  2. 解决我的问题的最佳方法是什么?为什么?
  3. 还有其他我应该使用或不应该使用的模式吗?我对 Promise 和异步 js 相当陌生,所以任何提示都会有帮助!

我检查过的主要教程

感谢您的帮助!


我的简化代码:

functionWhichReturnsPromise()
.then(function(user){
  var promises = [];
  Q.try(function(){
    for (var index in array) {
      var fbid = array[index];// Get fbid from array
      promises.push(Q.defer().promise); // Add promise to promise array

      // Find userid from fbid; resolve respective promise when finished
      User.findOne({facebook_id: fbid}).then(function(userSeen){
        promises[index].resolve(userSeen.id);
        sails.log('resolved where id=' + userSeen.id); // correct
        sails.log('resolved where index=' + index); // PROBLEM: always last index
      });
    }
  }).then(function(){

    // For debugging purposes
    Q.delay(1000).then(function(){
      sails.log(promises[0]); // Unresolved
      sails.log(promises[1]); // Unresolved
      sails.log(promises[2]); // Only last promise in array is resolved
    });

    // When the userids have been extracted from above (promises fulfilled)...
    Q.all(promises).then(function(seenids){
      // Do stuff here (Doesn't get here)
    });
  });
});

最佳答案

在 Javascript 中,变量的作用域是函数而不是大括号。

因此在下面的代码中,var index的作用域不是for循环的大括号,作用域实际上是for循环所在的函数。

Q.try(function(){
    for (var index in array) {
      var fbid = array[index];// Get fbid from array
      promises.push(Q.defer().promise); // Add promise to promise array

      // Find userid from fbid; resolve respective promise when finished
      User.findOne({facebook_id: fbid}).then(function(userSeen){
        promises[index].resolve(userSeen.id);
        sails.log('resolved where id=' + userSeen.id); // correct
        sails.log('resolved where index=' + index); // PROBLEM: always last index
      });
    }
  })

在 for 循环中,您调用异步函数,在您的情况下是 mongodb 调用 (findOne)。 您应该始终假设这些异步函数可以花费任意毫秒数来运行(取决于函数)。但一般来说,循环通常会在异步函数运行之前完成。即使在这些函数开始运行之前,您的 for 循环也会触发所有这些异步函数。问题是所有待处理的异步函数仍然指向该变量index。该变量对于所有变量都是通用的,因为 index 位于外部函数的范围内。

这是由于 Javascript 中的闭包而产生的问题。为了解决这个问题,我们需要使用更多的闭包。

您可以通过谷歌搜索有关闭包主题的许多资源。但请通过MDN's description of it .

如果您在循环内的另一个函数中捕获 index 的值,那么您就可以开始了。

这是我针对您的问题建议的解决方案。虽然我还没有测试过,但你明白了。

Q.try (function () {
    array.forEach( function(ele, idx, array) {
        (function(index) {
            var fbid = array[index]; // Get fbid from array
            promises.push(Q.defer().promise); // Add promise to promise array

            // Find userid from fbid; resolve respective promise when finished
            User.findOne({
                facebook_id : fbid
            }).then(function (userSeen) {
                promises[index].resolve(userSeen.id);
                sails.log('resolved where id=' + userSeen.id); // correct
                sails.log('resolved where index=' + index); // PROBLEM: always last index
            });
        })(idx);
    })
})

希望这有帮助。

另请注意: it is incorrect to use for...in for iterating through arrays .

关于node.js - 异步 Node.js 循环中的变量作用域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31196309/

相关文章:

node.js - 如何解决 Adonis 应用程序启动时的崩溃问题?

node.js - Sequelize 批量插入与关联

c# - 如何在没有回调的情况下异步发出 Web 请求

unit-testing - 如何用玩笑模拟 pg-promise 库

javascript - IndexedDB 事务和 Promises 之间的相互作用不一致

javascript - 如何检查sqlite3 Nodejs中是否存在表

node.js - 获取 Node 中插入设备的USB端口

c++ - 如何为 send() 和 select() 缓冲数据?

java - 要在异步调用上实现优雅的关闭检查锁定,还是要处理异常?

javascript - Q.all 返回异步函数而不是我想要解析的值