我有一个使用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个正确的消息顺序,即任何复合消息的子消息'插入复合消息在原始数组中的位置。
谢谢!
答案 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
一致的数组。