无法获得按顺序评估的承诺

Cannot get Promise to evaluate in sequence

我有一个购物车系统,其中请求的顺序非常重要。系统必须能够在将项目添加到用户帐户之前创建用户。为此,我使用了 promises 并尝试将它们链接起来,以便它们一个接一个地出现。也许我的理解有缺陷,但我没有让它发挥作用。

processUsers 函数。 Returns 一个承诺。这个函数的顺序也很重要,因为我们需要在开始将它们连接在一起之前按顺序创建所有用户帐户(在这个 child 和 parents 之间有一个 link系统)

this.createUsers 和 this.createUserRelations 都是 return Promise 列表

的函数
    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 完成,因此我得到一个错误,因为服务器找不到 link 项目的用户。 我知道 Promise.all() 不会 运行 连续承诺,但我认为它会启动 运行ning 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。我认为情况并非如此,但在我 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)
        })
    }

现在可以使用了!

I know that Promise.all() doesn't run promises in serial but I thought it would start running userPromises and once they are resolved it would run itemPromises.

不,承诺不是 "run",Promise.all 没有 "start" 任何东西。承诺只是您可以等待的事情,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)
//      ^^^^^^
    })
}