Q 承诺的递归
Recursion with Q promises
我有一个使用 promise 进行递归的场景,我需要一些帮助。
我有一个包含一系列消息的数组。每条消息可以是: 1 个原语,如字符串;或 2 复合,它只是指向包含一系列消息的 DB 区域的指针。例如,数组可以是:['hello', (compound), 'there']
,其中(compound)在从数据库中获取复合消息时可以包含['how', 'are', 'you']
。因此,最终的 'expanded' 数组看起来像:['hello', 'how', 'are', 'you', 'there']
。将消息数组完全转换为原始消息数组称为'expand'。
请注意,复合消息中的消息也可以是复合消息,这就是递归的用武之地。例如,如果上例中的(复合)是['how', 'are', 'you', (lower level compound)]
,并且(较低级别的复合)是['Tom', 'Jerry']
,那么(compound)会展开成['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
从数据库中获取复合消息的消息。
我应该如何承诺上面的代码,以便在外部承诺之后 returns:1 outputMessages 仅包含原始消息;并且维护了 2 个正确的消息顺序,也就是说,任何复合消息的 'submessages' 都被插入到复合消息在原始数组中的位置。
谢谢!
涉及 promises 的唯一原因是 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);
}, []);
};
说明
[].concat(messages)
是防止 messages
不是数组的安全措施,在这种情况下 messages.map()
会抛出。
.map(...)
将 Strings/Arrays/Promises 的混合数组映射到字符串和 Promises 的混合数组。
m.then(expandMessages)
和 fetchMessages(m).then(expandMessages)
导致递归发生。
Q.all()
聚合字符串和Promises的混合数组,传递字符串和数组的混合数组。
.then(flatten)
将字符串和数组的混合数组简化为字符串数组。
- 最终数组的顺序是您想要的,因为
Q.all(messages.map(...))
提供(在每个级别)与 messages
. 一致的数组
- 正如您将在演示中看到的,"compound message" 可以是 Array 或 promise-wrapped Array,它提供了一定程度的灵活性,您可能需要也可能不需要(但它是免费的)。
我有一个使用 promise 进行递归的场景,我需要一些帮助。
我有一个包含一系列消息的数组。每条消息可以是: 1 个原语,如字符串;或 2 复合,它只是指向包含一系列消息的 DB 区域的指针。例如,数组可以是:['hello', (compound), 'there']
,其中(compound)在从数据库中获取复合消息时可以包含['how', 'are', 'you']
。因此,最终的 'expanded' 数组看起来像:['hello', 'how', 'are', 'you', 'there']
。将消息数组完全转换为原始消息数组称为'expand'。
请注意,复合消息中的消息也可以是复合消息,这就是递归的用武之地。例如,如果上例中的(复合)是['how', 'are', 'you', (lower level compound)]
,并且(较低级别的复合)是['Tom', 'Jerry']
,那么(compound)会展开成['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
从数据库中获取复合消息的消息。
我应该如何承诺上面的代码,以便在外部承诺之后 returns:1 outputMessages 仅包含原始消息;并且维护了 2 个正确的消息顺序,也就是说,任何复合消息的 'submessages' 都被插入到复合消息在原始数组中的位置。
谢谢!
涉及 promises 的唯一原因是 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);
}, []);
};
说明
[].concat(messages)
是防止messages
不是数组的安全措施,在这种情况下messages.map()
会抛出。.map(...)
将 Strings/Arrays/Promises 的混合数组映射到字符串和 Promises 的混合数组。m.then(expandMessages)
和fetchMessages(m).then(expandMessages)
导致递归发生。Q.all()
聚合字符串和Promises的混合数组,传递字符串和数组的混合数组。.then(flatten)
将字符串和数组的混合数组简化为字符串数组。- 最终数组的顺序是您想要的,因为
Q.all(messages.map(...))
提供(在每个级别)与messages
. 一致的数组
- 正如您将在演示中看到的,"compound message" 可以是 Array 或 promise-wrapped Array,它提供了一定程度的灵活性,您可能需要也可能不需要(但它是免费的)。