0

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

我调用了返回一个数组对象的 Redis。然后,我遍历每个结果并回调 Redis 以获取一个值,并希望将这些填充到最终对象out中。

out 对象永远不会被填充,我猜测 forEach 尚未完成:

(注意 Redis 客户端库默认返回基于 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() 方法不包含完整的outobj。

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


更新 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 打印正确的键/值

key1 val1
key2 val2

最后完成的现在打印:

[ undefined, undefined ]
4

2 回答 2

0

重要的是要了解流程控制承诺链传达的数据由以下因素决定:

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

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] 承诺REDISCLIENT.get()都已成功解决时才会发生这种情况。

于 2015-07-20T06:50:56.023 回答
0

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

then您需要从您的-callback 中返回一个Promise,以便将内部 Promise 连接到外部 Promise。更具体地说,你需要一个超越所有内在承诺的承诺。

最简单的方法是使用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,而是console.log(out)在第一个承诺甚至解决之前立即调用。

于 2015-07-19T23:00:57.587 回答