Q承诺递归

时间:2018-02-03 03:57:40

标签: promise q

我有一个使用promises进行递归的场景,我需要一些帮助。

我有一个包含一系列消息的数组。每条消息可以是:1个原语,就像一个字符串;或2复合,它只是指向包含一系列消息的DB区域的指针。例如,数组可以是:['hello', (compound), 'there'],其中(复合)在从DB获取复合消息时可以包含['how', 'are', 'you']。因此,最终的扩展'数组看起来像:['hello', 'how', 'are', 'you', 'there']。将一组消息完全转换为原始消息数组称为“扩展”。

请注意,复合消息中的消息也可以是复合消息,这是递归进入的位置。例如,上面示例中的(复合)是['how', 'are', 'you', (lower level compound)],(低级复合)是['Tom', 'Jerry'],然后(复合)将展开为['how', 'are', 'you', 'Tom', 'Jerry'],原始数组将展开为['hello', 'how', 'are', 'you', 'Tom', 'Jerry', 'there']

以下是我认为代码的样子,没有承诺:

function expandMessages(messages, outputMessages) {
    messages.forEach(function(message) {
        if (message.primitive) {
            outputMessages.push(message);
        }
        else {
            var fetchedMessages = fetchMessages(message);
            expandMessages(fetchedMessages, outputMessages);
        }
    });
}

在上面的代码中,fetchMessages从DB中获取复合邮件的消息。

我应该如何宣传上述代码,以便在外部promise返回之后:1 outputMessages只包含原始消息;并保留2个正确的消息顺序,即任何复合消息的子消息'插入复合消息在原始数组中的位置。

谢谢!

1 个答案:

答案 0 :(得分:1)

涉及承诺的唯一原因是fetchMessages()是异步的,所以我们假设是这样。

代码非常简单:

function expandMessages(messages) {
    return Q.all([].concat(messages).map(function(m) {
        return Array.isArray(m) ? fetchMessages(m).then(expandMessages) : m.then ? m.then(expandMessages) : m;
    })).then(flatten);
}

其中flatten()是:

function flatten(list) {
    return list.reduce(function(a, b) {
        return a.concat(Array.isArray(b) ? flatten(b) : b);
    }, []);
};

<强> DEMO

解释

  • [].concat(messages)是一种安全措施,可防止messages不是数组,在这种情况下messages.map()会抛出。
  • .map(...)将字符串/数组/承诺的混合数组映射到字符串和承诺的混合数组。
  • m.then(expandMessages)fetchMessages(m).then(expandMessages)导致递归发生。
  • Q.all()聚合了Strings和Promises的混合数组,并提供了一个混合的字符串和数组数组。
  • .then(flatten)将字符串和数组的混合数组减少为字符串数组。
  • 最终数组的顺序是您想要的,因为Q.all(messages.map(...))提供(在每个级别)与messages一致的数组。
  • 正如您将在演示中看到的那样,&#34;复合消息&#34;可以是Array或promise-wrapped Array,它提供了一些您可能需要或可能不需要的灵活性(但它是免费的)。