Вложенные, асинхронные обещания: как узнать, когда они все решены? - PullRequest
0 голосов
/ 01 июля 2019

Я делаю несколько вызовов API из веб-приложения.Сначала я получаю информацию о моем партнере (группа отелей).У этого партнера есть некоторые свойства.Для каждого из этих свойств мне нужно получить свои комнаты;затем для каждой из этих комнат мне нужно получить их наличие и бронирование.Я хотел бы выполнить все эти вызовы асинхронно (то есть, как только я получу информацию о номере объекта, я смогу получить их заказы и информацию о наличии свободных мест, не дожидаясь получения сведений обо всех свойствах).Я хотел бы знать, когда все загружено.Ниже приведен упрощенный код, использующий тайм-ауты для имитации вызовов API.

Я пытался поместить каждое новое обещание в массив и использовать Promise.all для этого массива, но я столкнулся с той же проблемой.

Я также пытался увеличивать счетчик при каждом запросе и уменьшать счетчик при каждом его разрешении;это работает, но не кажется очень чистым?

        const getPartner = () => {
            const p = new Promise((resolve) => {
                setTimeout(() => {
                    console.log('getPartner finished');
                    resolve({
                        properties: [1, 2, 3],
                    });
                }, 1000);
            });
            return p;
        }

        const getRooms = () => {
            const p = new Promise((resolve) => {
                setTimeout(() => {
                    console.log('getRooms finished');
                    resolve([1, 2, 3]);
                }, 1000);
            });
            return p;
        }

        const getAvailabilities = () => {
            const p = new Promise((resolve) => {
                setTimeout(() => {
                    console.log('getAvailabilities finished');
                    resolve([1, 2, 3]);
                }, 1000);
            });
            return p;
        }

        const getBookings = () => {
            const p = new Promise((resolve) => {
                setTimeout(() => {
                    console.log('getBookings finished');
                    resolve([1, 2, 3]);
                }, 1000);
            });
            return p;
        }

        function main() {
            getPartner().then((partner) => {
                Promise.all([
                    partner.properties.forEach((property) => {
                        getRooms().then((rooms) => {
                            rooms.forEach((room) => {
                                getAvailabilities();
                                getBookings();
                            })
                        });
                    })
                ]).then(() => {
                    console.log('all finished');
                });
            });
        }

        main();

Я ожидаю, что «все закончено» будет отображаться в консоли последним.Вместо этого он показывает сразу после того, как «getPartner закончен»

Правка: вот что я попробовал со счетчиком:

const promises = [];

        const getPartner = () => {
            const p = new Promise((resolve) => {
                setTimeout(() => {
                    console.log('getPartner finished');
                    resolve({
                        properties: [1, 2, 3],
                    });
                }, 1000);
            });
            promises.push(p);
            return p;
        }

        const getRooms = () => {
            const p = new Promise((resolve) => {
                setTimeout(() => {
                    console.log('getRooms finished');
                    resolve([1, 2, 3]);
                }, 1000);
            });
            promises.push(p);
            return p;
        }

        const getAvailabilities = () => {
            const p = new Promise((resolve) => {
                setTimeout(() => {
                    console.log('getAvailabilities finished');
                    resolve([1, 2, 3]);
                }, 1000);
            });
            promises.push(p);
            return p;
        }

        const getBookings = () => {
            const p = new Promise((resolve) => {
                setTimeout(() => {
                    console.log('getBookings finished');
                    resolve([1, 2, 3]);
                }, 1000);
            });
            promises.push(p);
            return p;
        }

        function main() {
            getPartner().then((partner) => {
                partner.properties.map((property) => {
                    getRooms().then((rooms) => {
                        getAvailabilities();
                        getBookings();
                    })
                })
            })
            .then(() => {
                Promise.all(promises).then(() => {
                    console.log('all finished');
                });
            });
        }

        main();

1 Ответ

3 голосов
/ 01 июля 2019

Несколько проблем:

  • forEach ничего не возвращает, но вы должны вернуть массив - для подачи в Promise.all.

  • Используйте Promise.all в в каждом случае, когда у вас есть несколько обещаний

  • Возвращайте обещания всякий раз, когда вам нужно связать одно вthen обратный вызов

Вот как это будет работать:

function main() {
    getPartner().then((partner) => {
        return Promise.all(partner.properties.map((property) => {
            return getRooms().then((rooms) => {
                return Promise.all(rooms.map((room) => {
                    return Promise.all([getAvailabilities(), getBookings()]);
                }))
            });
        })).then(() => {
            console.log('all finished');
        });
    });
}
...