Вы когда-нибудь работали с промисами в JavaScript и разочаровывались, когда кто-то отвергал и все портил?

Вы пишете какой-то код на основе промисов, все идет как надо, а потом бум — одно маленькое промис отклоняется, и вся цепочка рушится.

Ваш код останавливается, и вы задаетесь вопросом, почему JavaScript не может просто проигнорировать эту маленькую заминку и продолжить свой веселый путь. Что ж, друг, у меня для тебя хорошие новости.

Познакомьтесь с Promise.allSettled(), вашим новым лучшим другом и обещанием, о котором вы даже не догадывались. Promise.allSettled() меняет правила игры, позволяя вам дождаться, пока все ваши обещания будут выполнены — либо разрешены, либо отклонены, — а затем действовать на основе результатов.

Больше никаких несостоявшихся цепочек обещаний или необработанных отказов. Просто чистое, неподдельное обещание блаженства. Присоединяйтесь ко мне, когда мы погрузимся в этот малоизвестный, но невероятно полезный метод промисов и посмотрим, насколько он может упростить ваш асинхронный код JavaScript.

Что такое Promise.allSettled()?

Итак, вы хотите использовать метод Promise.allSettled() в JavaScript, но не совсем уверены, как он работает и зачем вам его использовать? Не беспокойтесь, я вас прикрою.

Promise.allSettled() ждет выполнения всех обещаний, которые вы ему даете, что означает либо разрешение, либо отклонение. Затем он возвращает массив объектов со статусом и значением или причиной для каждого промиса.

Это полезно, когда у вас есть несколько асинхронных задач, которые вы хотите гарантировать, что они выполнены, но не обязательно заботиться о сбое некоторых из них.

Например, предположим, что у вас есть три вызова API, которые возвращают промисы, и вы хотите получить все данные из успешных вызовов, даже если один из них завершился неудачно. Вы можете сделать:

Promise.allSettled([apiCall1(), apiCall2(), apiCall3()]).then((results) => {});

Это запустит все три вызова API, а обратный вызов .then() будет вызван после того, как все они будут установлены. Массив результатов будет иметь три объекта: по одному для каждого обещания либо со статусом «выполнено» и данными, либо «отклонено» и ошибкой.

Мы можем отфильтровать, чтобы просто получить успешные вызовы, и продолжить использование этих данных.

Ключевые вещи, которые следует помнить:

  • Promise.allSettled() ожидает, пока все входные промисы будут установлены, и возвращает их результаты.
  • Урегулированный означает либо решенный (выполненный), либо отклоненный.
  • Он возвращает массив объектов со статусом и значением/причиной для каждого входного промиса.
  • Это позволяет обрабатывать успешные промисы, даже если некоторые из них отклоняются.

Проблема с Promise.all() и решение с Promise.allSettled()

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

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

К счастью, есть простое решение: Promise.allSettled(). Это работает аналогично Promise.all(), но вместо того, чтобы немедленно отклонять, если какое-либо обещание отклонено, он ждет, пока все обещания будут выполнены (либо разрешены, либо отклонены), а затем возвращает массив объектов со статусом и значением/причиной для каждого обещания.

Например:

Promise.allSettled([
  Promise.resolve(1),
  Promise.reject(new Error("2")),
  Promise.resolve(3),
]).then((results) => {
  // results is an array of:
  // {status: "fulfilled", value: 1}
  // {status: "rejected", reason: Error}
  // {status: "fulfilled", value: 3}
});

Как видите, несмотря на то, что второй промис отклонен, мы все равно получаем разрешенные значения из других промисов. Это позволяет корректно обрабатывать отказы, не пропуская ни одного успешного ответа.

Promise.allSettled() обеспечивает большую гибкость в подобных ситуациях. Вы получаете полную картину всех своих обещаний, независимо от того, какие из них были отклонены, поэтому у вас есть возможность по-прежнему использовать любые разрешенные значения и соответствующим образом обрабатывать отклонения.

Так что в следующий раз, когда вам нужно будет ждать несколько промисов, но вы не можете позволить себе пропустить какие-либо обработанные значения из-за отклонения, обязательно используйте Promise.allSettled()! Это очень полезное дополнение к Promise API.

Общие вопросы о Promise.allSettled()

Будет ли Promise.allSettled() замедлять мой код?

Не совсем. Promise.allSettled() просто ждет, пока все обещания, которые вы ему передадите, будут выполнены либо путем выполнения, либо отклонения. Он не делает ничего другого, что могло бы повлиять на производительность.

Могу ли я по-прежнему ловить ошибки с помощью Promise.allSettled()?

Да, вы абсолютно можете! Promise.allSettled() предоставит вам результат каждого обещания, независимо от того, было ли оно выполнено или отклонено.

Для любых отклоненных промисов вы получите причину, по которой они были отклонены, обычно это ошибка. Вы можете поймать эти ошибки в обработчике .catch() вызова Promise.allSettled().

Когда следует использовать Promise.allSettled() вместо Promise.all()?

Используйте Promise.allSettled(), когда вы хотите запустить несколько обещаний параллельно, но не хотите, чтобы одно отклоненное обещание вызывало отклонение всей группы.

Например, если вы получаете данные из нескольких сторонних API, отклоненное обещание от одного API не должно мешать вам получать данные из других API.

Используйте Promise.all(), когда вы хотите запускать промисы параллельно, но вам нужно, чтобы они все успешно завершились, чтобы ваш код продолжал работать.

Например, если вам нужно получить данные из двух API для отображения на странице, вы хотите, чтобы оба промиса выполнялись до рендеринга данных.

Могу ли я получить результаты выполненных обещаний?

Да! Promise.allSettled() возвращает массив объектов со статусом и значением/причиной для каждого промиса. Например:

Promise.allSettled([
  Promise.resolve(1),
  Promise.reject(new Error("2")),
  Promise.resolve(3),
]).then((results) => {
  console.log(results);
  /*
    [
      { status: "fulfilled", value: 1 },
      { status: "rejected", reason: Error: 2 },
      { status: "fulfilled", value: 3 }
    ]
    */
});

Вы получите информацию обо всех обещаниях, выполненных или отклоненных, так что у вас будет полная картина параллельных операций.

Заключение

Итак, у вас есть это. Promise.allSettled() — это удобный метод, о котором вы даже не догадывались.

Вам больше не нужно оборачивать Promise.all() в try/catch только для обработки возможных отклонений. Вы можете позволить Promise.allSettled() сделать все это за вас и просто сосредоточиться на разрешенных значениях. Ваш асинхронный код будет чище и легче для чтения.