Как использовать Promise.all()
JavaScript предоставляет вспомогательную функцию Promise.all(promisesArrayOrIterable) для одновременной, параллельной обработки нескольких промисов и получения результатов в одном агрегированном массиве. Посмотрим, как это работает.
Promise.all()
Содержание статьи:
Promise.all() — это встроенный хэлпер, который принимает массив промисов (или, как правило, итерацию).
JavaScript const allPromise = Promise.all([promise1, promise2, …]);
1 | const allPromise = Promise.all([promise1, promise2, …]); |
JavaScript. Быстрый старт
Изучите основы JavaScript на практическом примере по созданию веб-приложения
Затем вы можете извлечь значения промисов, используя синтаксис then-able:
JavaScript allPromise.then(values => { values; // [valueOfPromise1, valueOfPromise2, …] }).catch(error => { error; // rejectReason of any first rejected promise });
12345 | allPromise.then(values => { values; // [valueOfPromise1, valueOfPromise2, …]}).catch(error => { error; // rejectReason of any first rejected promise}); |
или синтаксис async/await:
JavaScript try { const values = await allPromise; values; // [valueOfPromise1, valueOfPromise2, …] } catch (error) { error; // rejectReason of any first rejected promise }
123456 | try { const values = await allPromise; values; // [valueOfPromise1, valueOfPromise2, …]} catch (error) { error; // rejectReason of any first rejected promise} |
Интересная часть заключается в том, как промис, возвращаемый функцией Promise.all(), разрешается или отклоняется. Если все промисы разрешены успешно, allPromise выполняется с массивом, содержащим выполненные значения отдельных промисов. Порядок промисов в массиве имеет значение — вы получите значения именно в этом порядке.
Но если хотя бы один промис отклоняется, то allPromise отклоняется сразу (не дожидаясь разрешения других промисов).
Давайте посмотрим на нескольких примерах, как использовать Promise.all() для одновременного выполнения нескольких асинхронных операций.
Пример: все промисы выполнены.
Чтобы изучить, как работает Promise.all(), я собираюсь использовать 2 функции — resolveTimeout(value, delay) и rejectTimeout(reason, delay).
JavaScript function resolveTimeout(value, delay) { return new Promise( resolve => setTimeout(() => resolve(value), delay) ); } function rejectTimeout(reason, delay) { return new Promise( (r, reject) => setTimeout(() => reject(reason), delay) ); }
1234567891011 | function resolveTimeout(value, delay) { return new Promise( resolve => setTimeout(() => resolve(value), delay) );} function rejectTimeout(reason, delay) { return new Promise( (r, reject) => setTimeout(() => reject(reason), delay) );} |
resolveTimeout(value, delay) возвращает промис, который выполняется по прошествии времени delay.
С другой стороны, rejectTimeout(reason, delay) возвращает промис, который отклоняется по причине reason (обычно с ошибкой) по прошествии времени delay.
JavaScript. Быстрый старт
Изучите основы JavaScript на практическом примере по созданию веб-приложения
Например, давайте получим доступ к спискам овощей и фруктов, доступных в местном продуктовом магазине. Доступ к каждому списку — асинхронная операция:
JavaScript const allPromise = Promise.all([ resolveTimeout([‘potatoes’, ‘tomatoes’], 1000), resolveTimeout([‘oranges’, ‘apples’], 1000)]); // wait… const lists = await allPromise; // after 1 second console.log(lists); // [[‘potatoes’, ‘tomatoes’], [‘oranges’, ‘apples’]]
1234567 | const allPromise = Promise.all([ resolveTimeout([‘potatoes’, ‘tomatoes’], 1000), resolveTimeout([‘oranges’, ‘apples’], 1000)]);// wait…const lists = await allPromise; // after 1 secondconsole.log(lists); // [[‘potatoes’, ‘tomatoes’], [‘oranges’, ‘apples’]] |
Попробуйте демо.
const allPromise = Promise.all([…]) возвращает новый allPromise.
Затем оператор const lists = await allPromise ожидает 1 секунду, пока не будет выполнен allPromise, содержащий значения выполнения первого и второго промисов.
Наконец, lists содержит агрегированный результат: [[‘potatoes’, ‘tomatoes’], [‘oranges’, ‘apples’]].
Порядок массива промисов напрямую влияет на порядок результатов. Промис из овощей это первый элемент, а промис из фруктов — второй элемент в массиве: Promise.all([vegetablesPromise, fruitsPromise]). Массив результатов содержит значения в том же порядке — первый список овощей и второй список фруктов.
Пример: один промис отклоняется.
А теперь представьте ситуацию, когда в магазине закончились фрукты. В таком случае давайте откажемся от промиса фруктов с ошибкой new Error(‘Out of fruits!’):
JavaScript const allPromise = Promise.all([ resolveTimeout([‘potatoes’, ‘tomatoes’], 1000), rejectTimeout(new Error(‘Out of fruits!’), 1000)]); try { // wait… const lists = await allPromise; } catch (error) { // after 1 second console.log(error.message); // ‘Out of fruits!’}
12345678910 | const allPromise = Promise.all([ resolveTimeout([‘potatoes’, ‘tomatoes’], 1000), rejectTimeout(new Error(‘Out of fruits!’), 1000)]); try { // wait… const lists = await allPromise;} catch (error) { // after 1 second console.log(error.message); // ‘Out of fruits!’} |
Попробуйте демо.
В сценарии allPromise = Promise.all([…]), как обычно, возвращается промис.
Однако по прошествии 1 секунды второй промис(фрукты) отклоняется с ошибкой new Error(‘Out of fruits!’). Это приведет к отказу new Error(‘Out of fruits!’).
Даже если промисы по овощам были выполнены, Promise.all() это не принимает во внимание.
Такое поведение Promise.all([…]) называется отказоустойчивым. Если хотя бы один промис в массиве отклоняется, то результат, возвращенный allPromise = Promise.all([…]) также отклоняется — по той же причине.
Вывод
Promise.all([…]) — полезная вспомогательная функция, которая позволяет выполнять асинхронные операции параллельно, используя стратегию безотказной работы, и объединять результаты в массив.
Автор: Dmitri Pavlutin
Источник: webformyself.com