Node.js/Javascript - 嵌套承诺和 for 循环 when.js

Node.js/Javascript - nested promises and for loop with when.js

我目前正在努力处理 promise 的控制流(promise 新手!)。

我调用 Redis,其中 returns 一个数组对象。然后我遍历每个结果并回调到 Redis 以获取一个值并希望将它们填充到最终对象 out.

从未填充 out 对象,我猜是因为 forEach 尚未完成:

(注意 Redis 客户端库 returns 默认基于 when.js 的承诺)

var out = {};

REDISCLIENT.keys("apikey:*")
    .then(function (replies) {

        replies.forEach(function (key, index) {

            REDISCLIENT.get(key)
                .then(function (value) {
                    out[key] = value;
                })
                .done(console.log(out));

        });

    })
    .catch(console.log)
    .done(console.log(out));

如何保证forEach循环完成?

我读过很多类似的帖子(我知道这是重复的)但是无法理解为什么内部 done() 方法不包含完整的 out obj。

我想我需要将 forEach 本身包装在一个 promise 中?欣赏任何方向。


更新 1:非常感谢@David_Aurelio。我现在需要用键和值填充 out。这是我的尝试:

GLOBAL.REDISCLIENT.keys("apikey:*")
        .then(function (replies) {
            return when.all(replies.map(function (key, index) {
                return GLOBAL.REDISCLIENT.get(key)
                    .then(function (val) {
                        out[key] = val;
                        console.log(key, val);
                    });
            }));
        })
        .catch(console.log)
        .done(function (out) {console.log(out); });

里面的console.log打印出正确的key/values

key1 val1
key2 val2

最后完成的现在打印:

[ undefined, undefined ]

forEach 循环完成,但您在 中创建的 Promise 没有。 when.js 实现Promises/A+ 规范,保证承诺回调的异步解析。这意味着,保证在当前调用堆栈完成执行后调用传递给 then() 的回调。

您需要 return 来自 then 回调的承诺,以便将内部承诺与外部承诺联系起来。更具体地说,你需要一个超越所有内心承诺的承诺。

最简单的方法是使用 when.all:

REDISCLIENT.keys("apikey:*")
  .then(function (replies) {
    return when.all(replies.map(function (key, index) {
      return REDISCLIENT.get(key);
    }));
  })
  .catch(console.log)
  .done(function (out) {console.log(out); });

在您的原始代码中,您也没有向 done 注册回调,而是在第一个 promise 尚未解决之前立即调用 console.log(out)

重要的是要了解流量控制 承诺链传送的数据由 :

决定
  • 链的组成,以及任何内部链
  • 承诺聚合器,例如 when.all()
  • return 语句

以下是如何使用 out 作为内部成员实现您想要的。

REDISCLIENT.keys("apikey:*")
.then(function (replies) {
    var out = {}: //<<<<< initiate `out` as an inner member
    return when.all(replies.map(function (key, index) { //<<<<< here's David Aurelio's when.all(replies.map(...))
        return REDISCLIENT.get(key).then(function (value) { //<<<<< `return` here causes `.map()` to build an array of promises.
            out[key] = value;
        });
    })).then(function() { //<<<< here's an additional `.then()` chained to `when.all(...)`
        return out; //<<<<< `return` here makes the populated `out` available to the `.done()` callback below.
    });
})
.catch(console.log)
.done(function (out_) {
    console.log(out_);
});

丑陋的外成员消失了!

.done() 回调中,我将成员名称更改为 out_ 以强调它已 通过 作为结果 return out,只有 当所有 [geddit] return 由 REDISCLIENT.get() 调用的承诺已成功结算时才会发生。