Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Promise.all() у JavaScript». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`Promise.all()` приймає ітерований набір промісів і повертає новий проміс, який виконується успішно лише тоді, коли виконались геть усі вхідні проміси; його значення - масив результатів у порядку передання, а не в порядку завершення. Якщо хоча б один проміс відхиляється, спільний проміс відхиляється негайно (fail-fast) з причиною цього першого відхилення, а решта промісів усе одно доїжджають до кінця, просто їхні результати ігноруються.** ```javascript Promise.all([Promise.resolve('OK'), Promise.reject('Помилка!')]) .then(r => console.log(r)) .catch(err => console.error(err)); // Помилка! ``` **Ключове:** `Promise.all()` це «все або нічого»: перша ж помилка відхиляє весь результат, тож коли потрібні всі відповіді незалежно від збоїв, беріть `Promise.allSettled()`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`Promise.all()` це статичний метод класу `Promise`, який приймає масив (або будь-який ітерований об'єкт) промісів і повертає новий проміс.** Цей проміс виконується успішно (`fulfilled`), коли всі проміси зі списку завершились успішно, і відхиляється (`rejected`) щойно перший із них завершився з помилкою. ## Теорія ### TL;DR - `Promise.all(iterable)` повертає новий проміс, який агрегує список промісів. - `fulfilled`: коли всі вхідні проміси стали `fulfilled`. Значення це масив результатів **у тому самому порядку**, у якому проміси передали, а не в порядку завершення. - `rejected`: одразу після першого відхилення, з причиною саме цього відхилення (поведінка fail-fast). - Решта промісів не скасовуються, вони виконуються до кінця, але їхні результати вже ніхто не побачить. - Звичайні значення (не проміси) автоматично загортаються через `Promise.resolve()`. - Потрібні всі результати навіть із помилками? Тоді `Promise.allSettled()`, який не відхиляється ніколи. ### Швидкий приклад ```javascript const p1 = Promise.resolve('A'); const p2 = Promise.resolve('B'); const p3 = Promise.resolve('C'); // Проміс від Promise.all чекає на всі три одразу. Promise.all([p1, p2, p3]).then(values => console.log(values)); // ["A", "B", "C"] ``` Синтаксис максимально простий: ```javascript Promise.all(iterable) ``` де `iterable` це, як правило, масив промісів. ### Як воно працює 1. Усі проміси всередині `Promise.all([...])` виконуються **паралельно**: точніше, кожен із них уже стартував *незалежно від інших*, бо проміс починає роботу в момент створення. 2. `Promise.all()` лише **чекає** на їхнє завершення, він нічого не запускає сам. 3. Якщо всі завершились успішно, повертається новий проміс у стані `fulfilled`, а його значення це **масив результатів у тому самому порядку**, що й вхідні проміси. Приклад із затримками: ```javascript const p1 = new Promise(res => setTimeout(() => res('Перший'), 1000)); const p2 = new Promise(res => setTimeout(() => res('Другий'), 2000)); const p3 = new Promise(res => setTimeout(() => res('Третій'), 500)); Promise.all([p1, p2, p3]) .then(results => console.log('Результати:', results)) .catch(err => console.error('Помилка:', err)); ``` Вивід приблизно через 2 секунди, тобто за часом найповільнішого проміса, а не за сумою всіх затримок: ```javascript Результати: [ 'Перший', 'Другий', 'Третій' ] ``` ### Порядок результатів і не проміси Результати впорядковані **за позицією** у вхідному масиві, навіть якщо один проміс виконується суттєво довше за інші: ```javascript Promise.all([ Promise.resolve('A'), new Promise(res => setTimeout(() => res('B'), 2000)), Promise.resolve('C') ]).then(console.log); // ["A", "B", "C"] ``` Якщо у масиві трапляються не проміси, `Promise.all()` автоматично «загортає» звичайні значення у `Promise.resolve()`: ```javascript Promise.all([42, Promise.resolve('OK')]) .then(console.log); // [42, "OK"] ``` ### Що станеться, якщо один із промісів відхилиться Якщо **хоча б один** проміс усередині `Promise.all` перейде у стан **rejected**, увесь `Promise.all()` **негайно відхиляється**, а результатом буде **перша спіймана помилка**. ```javascript const p1 = Promise.resolve('OK'); const p2 = Promise.reject('Помилка!'); const p3 = Promise.resolve('Ще OK'); Promise.all([p1, p2, p3]) .then(results => console.log('Успіх:', results)) .catch(err => console.error('Відхилено:', err)); ``` Вивід: ```javascript Відхилено: Помилка! ``` Решта промісів (`p1`, `p3`) усе одно виконаються, але **їхні результати ігноруються**, бо `Promise.all()` уже перейшов у стан **rejected**, а проміс змінює стан лише один раз. ### Як обробити помилки, не перериваючи виконання Якщо потрібно, щоб **усі проміси відпрацювали незалежно**, а помилки **не переривали** загальний результат, використовуйте `Promise.allSettled()`: ```javascript Promise.allSettled([ Promise.resolve('OK'), Promise.reject('Помилка'), Promise.resolve('Ще OK') ]).then(console.log); ``` Вивід: ```javascript [ { status: "fulfilled", value: "OK" }, { status: "rejected", reason: "Помилка" }, { status: "fulfilled", value: "Ще OK" } ] ``` `Promise.allSettled()` **не відхиляється ніколи** і повертає масив об'єктів з полями `status` та `value` або `reason`. Альтернатива для `Promise.all()`, якщо ви все ж хочете лишитись на ньому: перехопіть помилку в кожному промісі окремо, тоді жодне відхилення не дійде до агрегатора. ```javascript const safe = p => p.catch(err => ({ error: err })); Promise.all([p1, p2, p3].map(safe)).then(console.log); ``` ### Порівняння: all, allSettled, race | Метод | Що робить | Успіх | Помилка | | --- | --- | --- | --- | | `Promise.all()` | Чекає, поки виконаються всі проміси | Повертає масив результатів | Відхиляється на першій же помилці | | `Promise.allSettled()` | Чекає на всіх, навіть із помилками | Повертає масив об'єктів `{status, value/reason}` | Не відхиляється ніколи | | `Promise.race()` | Повертає результат **першого завершеного** проміса | Може бути і успіх, і помилка | Відхиляється, якщо першим завершився відхилений проміс | Проста аналогія: > Уявіть, що ви чекаєте на три доставки: > > - `Promise.all()`: ви чекаєте на **всі посилки разом**. Якщо хоча б одна **загубилась**, ви **скасовуєте все замовлення**. > - `Promise.allSettled()`: ви так само чекаєте на **всі**, і навіть якщо одна **пошкоджена**, ви все одно отримуєте звіт про кожну. ### Типові помилки - **Думати, що `Promise.all()` запускає проміси.** Він лише чекає: проміси стартували ще в момент створення, тому обгортка нічого не паралелізує додатково. - **Забути `.catch()` або `try/catch`.** Відхилення всередині `Promise.all()` без обробника дає `unhandled promise rejection`, а в Node.js це може завалити процес. - **Очікувати, що інші проміси скасуються.** Проміси не скасовні: після першого відхилення решта далі працює, споживає ресурси і може навіть кинути власну необроблену помилку. - **Чекати результати в порядку завершення.** Порядок у масиві завжди відповідає порядку входу, тому не сортуйте результати «за швидкістю». - **Використовувати `Promise.all()` там, де потрібні часткові результати.** Якщо один із десяти запитів має право впасти, беріть `Promise.allSettled()`. - **Передавати вже відхилений проміс у масив зарано.** Наприклад, створивши `Promise.reject()` заздалегідь і передавши його в `Promise.all()` пізніше, ви ризикуєте отримати необроблене відхилення ще до виклику.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.