我有一个购物车系统,其中请求的顺序非常重要。该系统必须能够创建用户,然后才能向其用户帐户添加项目。为此,我使用了诺言,并试图将它们链接起来,以便它们一个接一个地出现。也许我的理解是有缺陷的,但是我没有使它起作用。
processUsers函数。返回承诺。此功能的顺序也很重要,因为我们需要按顺序创建所有用户帐户,然后才能将它们连接在一起(此系统中的孩子和父母之间存在链接)
this.createUsers和this.createUserRelations都是返回承诺列表的函数
processUsers(child, parents) {
return new Promise((resolve, reject) => {
Promise.all(
this.createUsers(child, parents)
).then((userResponse) => {
Promise.all(
this.createUserRelations(
child,
parents
)
).then((relationResponse) => {
resolve(relationResponse)
}).catch(reject)
}).catch(reject)
})
}
这有效。这是正确的顺序。我正在通过使服务器上的create_or_update函数休眠5秒钟来进行测试,实际上createUserRelations函数正在等待该行为。
创建用户后,我使用相同的逻辑向每个用户添加项目
/**
* process a single ticket
* @param {Array} ticket
*/
processTicket(ticket) {
var self = this
return new Promise((resolve, reject) => {
var ticketUser = {}
const userPromises = ticket.filter(
(t) => t.item.item_type === ITEM_TYPE_TICKET
).map((m) => {
ticketUser = m.user
return self.processUsers(m.user, m.parents)
})
const itemPromises = ticket.map(
(t) => {
if(t.item.item_type === ITEM_TYPE_BUS) {
t.user = ticketUser
}
return self.processItem(t)
}
)
Promise.all(userPromises).then((data) => {
Promise.all(itemPromises).then((data) => {
resolve(data)
}).catch(reject)
}).catch(reject)
})
}
这不起作用。 itemPromises不等待userPromises完成,因此我收到一个错误消息,因为服务器找不到与之链接的用户。 我知道Promise.all()不会按顺序运行Promise,但我认为它将开始运行userPromises,一旦解决它们,它将运行itemPromises。似乎它没有这样做。 我已经尝试了其他多种方法,例如使用p-queue。
这是processItem函数
processItem(item) {
// returns a Promise
return users.add_order_item(
this.sessionUser.id,
item.user.email,
item.item.id,
item.delivery
)
}
最后是处理整个订单的票证的主要功能
processOrder() {
const items = this.orderSessionItems
const reduced = this.groupBy(
items, (i) => i.reference_number)
var self = this
const promises = Object.keys(reduced).map((key, index) => {
return self.processTicket(reduced[key])
})
return Promise.all(promises)
}
更新:事实证明我确实误解了Promises的工作方式。在processTicket中映射列表(两次)时,将立即调用processItem承诺。我以为不是这样,而是在Promise.all()之前调用它。
我最终得到的是这个
processTicket(ticket) {
return new Promise((resolve, reject) => {
var self = this
var ticketUser = {}
const userPromises = ticket.filter(
(t) => t.item.item_type === ITEM_TYPE_TICKET
).map((m) => {
ticketUser = m.user
return self.processUsers(m.user, m.parents)
})
Promise.all(userPromises).then(() => {
const itemPromises = ticket.map(
(t) => {
if(t.item.item_type === ITEM_TYPE_BUS) {
t.user = ticketUser
}
return self.processItem(t)
}
)
Promise.all(itemPromises)
.then((data) => resolve(data))
.catch(reject)
}).catch(reject)
})
}
现在可以使用了!
答案 0 :(得分:2)
我知道Promise.all()不会按顺序运行Promise,但是我认为它将开始运行userPromises,一旦解决它们,它将运行itemPromises。
不,诺言不会“运行”,Promise.all
不会“开始”任何事情。一个承诺只是您可以等待的事情,Promise.all
将这些事情中的多个因素组合成一个可以等待的承诺。
当您致电processItem()
时,这项工作正在开始,您确实会立即致电。如果您在then
回调中进行调用,它将在开始处理项目之前等待userPromises
。
顺便说一句,也请避免使用Promise
constructor antipattern:
processTicket(ticket) {
var ticketUser = {}
const userPromises = ticket.filter((t) =>
t.item.item_type === ITEM_TYPE_TICKET
).map((m) => {
ticketUser = m.user
return this.processUsers(m.user, m.parents)
})
return Promise.all(userPromises).then(() => {
// ^^^^^^
const itemPromises = ticket.map((t) => {
if(t.item.item_type === ITEM_TYPE_BUS) {
t.user = ticketUser
}
return this.processItem(t)
})
return Promise.all(itemPromises)
// ^^^^^^
})
}