节点承诺循环等待结果

时间:2016-09-12 12:30:40

标签: javascript node.js asynchronous promise

我如何等待for循环进入下一个循环?

如何确保执行userdetails并在传递新变量之前将realresult.playername分配给新变量?

代码:

return new Promise( function (resolve, reject) {

    arr = [];


    messages.find({convid: convid}).then(function(result) {

        for(var a in result) {
            realresult = result[a];

            userData.userDetails(realresult.userid).then(function (result) {
                realresult.playername = result.username;
            });
            userData.usercashinfo(realresult.userid).then(function (resulttwo) {
                realresult.playerdetails = resulttwo;
            });

            arr.push(realresult);

        }

        return resolve(arr);
    });
});

2 个答案:

答案 0 :(得分:1)

您正在尝试编写一个承诺,当它结算时,返回已解析的承诺值数组。你应该在这里做两件事:

  1. 使用return等待承诺的完成。在承诺链中,除非是return,否则实际上没有任何内容可以解析承诺值。 (您也应该将此用于message.find(),因为它也会给您一个承诺。)
  2. 将数组构造为一个promises数组,而不是迭代并在它们解析时将promises推入数组。
  3. 使用Promise.all()收集承诺对象 - all()仅在传递给它的所有承诺都已解决后才返回。
  4. (可选)不要重复使用result变量名来表示多个内容。这里没有错,但它可能导致不必要的混淆。
  5. 放在一起,这看起来像是:

    return messages.find(...).then(function(result) {
      var promiseArr = [];
      for (var a in result) {
        promiseArr.push(
          promise.all([userData.userDetails(...), userData.usercashinfo(...)])
          .then(function(detailinfo) {
            var realresult = result[a];
            var details = detailinfo[0];
            var cashinfo = detailinfo[1];
            realresult.playername = details.username;
            realresult.playerdetails = cashinfo;
            return realresult;
        });
      }
      return Promise.all(promiseArr);
    });
    

答案 1 :(得分:0)

所以我认为尝试使用生成器和承诺来解决它是一个好主意,我不确定它是最好的方法,但它是两者结合的好习惯所以我试一试。

这个想法是生成器函数在开始新的迭代之前等待回调函数,并且回调函数在告诉生成器函数继续迭代之前等待两个promise完成。

here is a more simple example that I first tried on codepen

return new Promise( function (resolve, reject) {
    arr = [];
    messages.find({convid: convid}).then(function(result) {
        function* iterations() {
            for (var i = 0; i < result.length; i++) {
                realresult = result[i];
                try {
                    var cbResult = yield cb(result[i].userid);
                    realresult.playername = cbResult.playername;
                    realresult.playerdetails = cbResult.playerdetails;
                    arr.push(realresult);
                } catch (e) { reject(e) }
            }
            return arr.value;
        }

        var it = iterations();
        it.next();

        function cb(userid) {
            Promise.all([
                       userData.userDetails(userid),
                       userData.usercashinfo(userid)
                       ]).then(
                           function(values) {
                               var realresult = {playername : values[0], playerdetails : values[1]}
                               returnValue = it.next(realresult);
                               if (returnValue.done) {
                                   resolve(returnValue);
                               }
                           },
                           function(e) { reject(e) }
                       );
        }
    });
});