Невозможно получить обещание оценить в последовательности - PullRequest
0 голосов
/ 07 апреля 2019

У меня есть система корзины покупок, где порядок запросов очень важен.Система должна иметь возможность создавать пользователей, прежде чем она добавит элементы в свою учетную запись.Для этого я использую обещания и пытаюсь связать их так, чтобы они появлялись одно за другим.Может быть, мое понимание неверно, но я не получаю это работать.

Функция 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 () не запускает обещания в последовательном режиме, но я думал, что он запустит userPromises, и как только они будут решены, он запустит itemPromises.Кажется, он этого не делает.Я пробовал несколько других вещей, таких как использование p-очереди.

Вот функция 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)
    }

ОБНОВЛЕНИЕ: Оказывается, я действительно неправильно понял, как работают Обещания.При отображении списка (два раза) в 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)
        })
    }

и теперь он работает!

1 Ответ

2 голосов
/ 07 апреля 2019

Я знаю, что Promise.all () не запускает обещания в последовательном режиме, но я думал, что он запустит userPromises, и как только они будут разрешены, он запустит itemPromises.

Нет,обещания не выполняются, Promise.all ничего не запускает.Обещание - это просто то, чего вы можете ждать, и Promise.all объединяет несколько этих вещей в одно обещание, которого вы можете ждать.

Работа начинается, когда вы звоните processItem(), и вы делаетепозвони немедленно.Если вы выполняете вызовы внутри обратного вызова then, он будет ждать userPromises, прежде чем начнет обрабатывать элементы.

Кстати, также избегайте использования Promise конструктора 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)
//      ^^^^^^
    })
}
...