Promise race своими руками

Promise race своими руками

Функции Promise.all() , Promise.allSettled() и Promise.race() позволяют сгруппировать выполнение нескольких промисов.

Функция Promise.all

Функция Promise.all() возвращает единый объект Promise , который объединяет набор промисов.

Рассмотрим следуюший код:

Здесь определено два промиса. Асинхронная операция ервого промиса выполняется через 500 миллисекунд, действие второго промиса выполняется через 1000 миллисекунд. Оба этих промиса выполняются независимо друг от друга. Общая продолжительность обоих промисов займет 1500 миллисекунд (500 — первый + 1000 второй)

Функция Promise.all() позволяет объединить несколько промисов и выполнять их параллельно, но как единое целое. В качестве параметра функция принимает набор промисов:

Возвращаемым результатом функции является новый объект Promise .

Теперь изменим предыдущий пример, использовав функцию Promise.all() :

Теперь данные обоих промисов возвращаются вместе и доступны в методе then() в виде массива values . Причем общее время выполнения составляет время выполнения наиболее продолжительнного промиса — то есть в данном случае 1000 миллисекунд (вместо прежних 1500 миллисекунд).

Значения всех промисов возвращаются только если все они завершились успешно. Но если в асинхронной операции хотя бы одного промиса возникнет ошибка в силу внутренней логики или из-за вызова функции reject() , то все промисы перейдут в состояние rejected , соответственно:

В данном случае мы явным образом переводим переводим первый промис в состояние rejected , соответственно в это состояние переводятся все промисы, переданные в функцию Promise.all() . И далее через метод catch() , как и в обзем случае, мы можем обработать возникшую ошибку.

Promise.allSettled

Еще одна функция — Promise.allSettled() также как и Promise.all() принимает набор промисов и выполняет их как единое целое, но возвращает объект со статусом и результатом промиса:

При этом при возникновении ошибки в одном из промисов (как в случае выше с первым промисом) функция также передается результаты в метод then() , который следует дальше в цепочке. Каждый результат представляет объект. Первое свойство этого объекта — status описывает статус или состояние промиса. Если произошла ошибка, статус rejected , а второе свойство представляет объект ошибки. Если промис успешно завершил выполнение, то статус fulfilled , а второе свойство — value хранит результат промиса.

Promise.race

Функция Promise.race() также принимает несколько промисов, только возвращает первый завершенный промис (вне зависимости завершился от успешно или с ошибкой):

В данном случае первым выполненным будет промис promise1 . Поэтому в метод then(value => console.log(value)) в качестве value будет передана строка «Hello».

Promise.any

Функция Promise.any() принимает несколько промисов и возвращает первый успешно завершившийся промис:

В данном случае первым выполненным будет промис promise1 , однако он завершается с ошибкой. Поэтому в метод then(value => console.log(value)) в качестве value будет передана строка «World» — результат промиса promise2, который успешно завершается.

Может показаться, что Promise.any() делает то же самое, что и Promise.race() , однако эти функции отличаются в отношении того, как они работают с промисами, которые завершились с ошибкой. Promise.race() возвращает первый завершенный промис, вне зависимости завершился он с ошибкой или нет. А Promise.any() возвращает первый успешно завершенный промис (если такой имеется). Если же все промисы завершились с ошибкой, то генерируется исключение типа AggregateError :

С помощью свойства errors типа AggregateError можно получить в виде массива все ошибки, которые возникли в промисах:

Источник

Promise API

В классе Promise есть 5 статических методов. Давайте познакомимся с ними.

Promise.all

Допустим, нам нужно запустить множество промисов параллельно и дождаться, пока все они выполнятся.

Например, параллельно загрузить несколько файлов и обработать результат, когда он готов.

Для этого как раз и пригодится Promise.all .

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

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

Например, Promise.all , представленный ниже, выполнится спустя 3 секунды, его результатом будет массив [1, 2, 3] :

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

Читайте также:  Как сделать полку для ванной своими руками

Часто применяемый трюк – пропустить массив данных через map-функцию, которая для каждого элемента создаст задачу-промис, и затем обернёт получившийся массив в Promise.all .

Например, если у нас есть массив ссылок, то мы можем загрузить их вот так:

А вот пример побольше, с получением информации о пользователях GitHub по их логинам из массива (мы могли бы получать массив товаров по их идентификаторам, логика та же):

Если любой из промисов завершится с ошибкой, то промис, возвращённый Promise.all , немедленно завершается с этой ошибкой.

Здесь второй промис завершится с ошибкой через 2 секунды. Это приведёт к немедленной ошибке в Promise.all , так что выполнится .catch : ошибка этого промиса становится ошибкой всего Promise.all .

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

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

Promise.all ничего не делает для их отмены, так как в промисах вообще нет концепции «отмены». В главе Fetch: прерывание запроса мы рассмотрим AbortController , который помогает с этим, но он не является частью Promise API.

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

Например, здесь результат: [1, 2, 3]

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

Promise.allSettled

Promise.all завершается с ошибкой, если она возникает в любом из переданных промисов. Это подходит для ситуаций «всё или ничего», когда нам нужны все результаты для продолжения:

Метод Promise.allSettled всегда ждёт завершения всех промисов. В массиве результатов будет

Например, мы хотели бы загрузить информацию о множестве пользователей. Даже если в каком-то запросе ошибка, нас всё равно интересуют остальные.

Используем для этого Promise.allSettled :

Массив results в строке (*) будет таким:

То есть, для каждого промиса у нас есть его статус и значение/ошибка.

Полифил

Если браузер не поддерживает Promise.allSettled , для него легко сделать полифил:

В этом коде promises.map берёт аргументы, превращает их в промисы (на всякий случай) и добавляет каждому обработчик .then .

Этот обработчик превращает успешный результат value в , а ошибку error в . Это как раз и есть формат результатов Promise.allSettled .

Затем мы можем использовать Promise.allSettled , чтобы получить результаты всех промисов, даже если при выполнении какого-то возникнет ошибка.

Promise.race

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

Например, тут результат будет 1 :

Быстрее всех выполнился первый промис, он и дал результат. После этого остальные промисы игнорируются.

Promise.resolve/reject

Методы Promise.resolve и Promise.reject редко используются в современном коде, так как синтаксис async/await (мы рассмотрим его чуть позже) делает его, в общем-то, не нужным.

Мы рассмотрим их здесь для полноты картины, а также для тех, кто по каким-то причинам не может использовать async/await .

  • Promise.resolve(value) создаёт успешно выполненный промис с результатом value .

То же самое, что:

Этот метод используют для совместимости: когда ожидается, что функция возвратит именно промис.

Например, функция loadCached ниже загружает URL и запоминает (кеширует) его содержимое. При будущих вызовах с тем же URL он тут же читает предыдущее содержимое из кеша, но использует Promise.resolve , чтобы сделать из него промис, для того, чтобы возвращаемое значение всегда было промисом:

Мы можем писать loadCached(url).then(…) , потому что функция loadCached всегда возвращает промис. Мы всегда можем использовать .then после loadCached . Это и есть цель использования Promise.resolve в строке (*) .

Promise.reject

  • Promise.reject(error) создаёт промис, завершённый с ошибкой error .

То же самое, что:

На практике этот метод почти никогда не используется.

Итого

Мы ознакомились с пятью статическими методами класса Promise :

Источник

Напишите функцию, поведение которой аналогично поведению Promise.race(promises)

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Напишите функцию, аргументом которой является функция f
Напишите функцию, аргументом которой является функция F, а результатом — функция, которая.

Напишите функцию Swap(a, b), аргументами которой могут быть числа любого типа
Напишите функцию Swap(a, b), аргументами которой могут быть числа любого типа. Функция меняет.

Читайте также:  Дача участок дизайн своими руками

Напишите функцию, которая возвращает объем сферы, радиус которой передается как параметр
1)Напишите функцию, которая возвращает объем сферы, радиус которой передается как параметр. .

Promise, два ajax запроса, задать очередь выполнения запросов, цепочка promise
Добрый день, уважаемые форумчане! Помогите разобраться с цепочкой promise. Суть проблемы: Есть.

Пикантность данной задачи заключается в том, что сам смысл метода Promise.race() изначально испорчен.
Лучше сразу выпрямить идею.

Повторим в JavaScript процесс приготовления завтрака.
1. Налить чашку кофе.
2. Нагреть сковородку, а затем поджарить два яйца.
3. Поджарить три куска бекона.
4. Сделать два тоста.
5. Намазать тосты маслом и джемом.
6. Налить стакан апельсинового сока.
Асинхронная модель программирования задач в C#

Более правильный смысл функции поиска первого завершенного промиса:
Возвращаемый функцией промис будет завершен, когда любой из последовательности промисов завершен.
Возвращаемый функцией промис всегда будет завершаться в состоянии resolved.
Это справедливо, даже если первый завершенный промис находится в состоянии rejected.

Поскольку в JavaScript результат промиса не может быть промисом, то
результат возвращенного промиса — массив из одного элемента: первого завершенного промиса.

Источник

Разбираемся с промисами в JavaScript

Доброго времени суток, Хабр! Представляю вашему вниманию перевод статьи «Understanding Promises in JavaScript» автора Sukhjinder Arora.

От автора перевода: Так же, как и сам автор, я надеюсь, что статья оказалась для вас полезной. Пожалуйста, если она и вправду помогла вам узнать для себя что-то новое, то не поленитесь зайти на оригинал статьи и поблагодарить автора! Буду рад вашему фидбеку!

JavaScript — это однопоточный язык программирования, это означает, что за раз может быть выполнено что-то одно. До ES6 мы использовали обратные вызовы, чтобы управлять асинхронными задачами, такими как сетевой запрос.

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

Предположим, что мы хотим асинхронно получить некоторые данные с сервера, используя обратные вызовы мы сделали бы что-то вроде этого:

Здесь я запрашиваю некоторые данные с сервера при помощи функции getData(), которая получает данные внутри функции обратного вызова. Внутри функции обратного вызова я запрашиваю дополнительные данные при помощи вызова функции getMoreData(), передавая предыдущие данные как аргумент и так далее.

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

Мы можем переписать приведенный выше фрагмент используя промисы:

Вы можете видеть, что стало более читабельно, чем в случае первого примера с обратными вызовами.

Что такое Промисы?

Промис(Обещание) — это объект который содержит будущее значение асинхронной операции. Например, если вы запрашиваете некоторые данные с сервера, промис обещает нам получить эти данные, которые мы сможем использовать в будущем.

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

Состояния промисов

Промис в JavaScript, как и обещание в реальной жизни, имеет 3 состояния. Это может быть 1) нерешенный(в ожидании), 2) решенный/resolved (выполненный) или 3) отклоненный/rejected.

Нерешенный или Ожидающий — Промис ожидает, если результат не готов. То есть, ожидает завершение чего-либо(например, завершения асинхронной операции).
Решенный или Выполненный — Промис решен, если результат доступен. То есть, что-то завершило свое выполнение(например, асинхронная операция) и все прошло хорошо.
Отклоненный — Промиc отклонен, если произошла ошибка в процессе выполнения.

Теперь мы знаем, что такое Промис и его терминологию, давайте вернемся назад к практической части промисов.

Создаем Промис

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

Мы создали новый промис, используя конструктор Промисов, он принимает один аргумент, обратный вызов, также известный как исполнительная функция, которая принимает 2 обратных вызова, resolve и reject.

Исполнительная функция выполняется сразу же после создания промиса. Промис становится выполненным при помощи вызова resolve(), а отклоненным при помощи reject(). Например:

resolve() и reject() принимают один аргумент, который может быть строкой, числом, логическим выражением, массивом или объектом.

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

Здесь я создал новый промис используя конструктор Промисов. Промис выполняется или отклоняется через 2 секунды после его создания. Промис выполняется, если randomNumber меньше, чем .6 и отклоняется в остальных случаях.

Когда промис был создан, он будет в состоянии ожидания и его значение будет undefined.

Читайте также:  Бизнес своими руками быстро

После 2 секунд таймер заканчивается, промис случайным образом либо выполняется, либо отклоняется, и его значением будет то, которое передано в функцию resolve или reject. Ниже пример двух случаев:

Примечание: Промис может быть выполнен или отклонен только один раз. Дальнейшие вызовы resolve() или reject() никак не повлияют на состояние промиса. Пример:

Так как resolve() была вызвана первой, то промис теперь получается статус “выполненный”. Последующий вызов reject() никак не повлияет на состояние промиса.

Использование Промиса

Теперь мы знаем как создавать промисы, давайте теперь разберемся как применять уже созданный промис. Мы используем промисы при помощи методов then() и catch().

Например, запрос данных из API при помощи fetch, которая возвращает промис.

.then() синтаксис: promise.then(successCallback, failureCallback)

successCallback вызывается, если промис был успешно выполнен. Принимает один аргумент, который является значением переданным в resolve().

failureCallback вызывается, если промис был отклонен. Принимает один аргумент, который является значением преданным в reject().

Если промис был выполнен, то вызывается successCallback со значением, переданным в resolve(). И если промис был отклонен, то вызывается failureCallback со значением, переданным в reject().

.catch() синтаксис: promise.catch(failureCallback)

Мы используем catch() для обработки ошибок. Это более читабельно, нежели обработка ошибок внутри failureCallback внутри обратного вызова метода then().

Цепочка промисов

Методы then() и catch() также могут возвращать новый промис, который может быть обработан цепочкой других then() в конце предыдущего метода then().

Мы используем цепочку промисов, когда хотим выполнить последовательность промисов.

И так, что тут происходит?

Когда promise1 выполнен, вызывается метод then(), который возвращает promise2.
Далее, когда выполнен promise2, снова вызывается then() и возвращает promise3.

Так как promise3 отклонен, вместо следующего then(), вызывается catch(), который и обрабатывает отклонение promise3.

Примечание: Как правило достаточно одного метода catch() для обработки отклонения любого из промисов в цепочке, если этот метод находится в конце неё.

Распространенная ошибка

Достаточно много новичков делают ошибку, вкладывая одни промисы внутрь других. Например:

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

Promise.all( )

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

Здесь аргументом внутри then() выступает массив, который содержит значения промисов в том же порядке, в котором они передавались в Promise.all().(Только в том случае, если все промисы выполняются)

Промис отклоняется с причиной отклонения первого промиса в переданном массиве. Например:

Здесь у нас есть два промиса, где один выполняется через 2 секунды, а другой отклоняется через 1.5 секунды. Как только второй промис отклоняется, возвращенный от Promise.all() промис отклоняется не дожидаясь выполнения первого.

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

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

Promise.race( )

Этот метод принимает массив промисов и возвращает один новый промис, который будет выполненным, как только встретится выполненный промис в массиве или же отклоняется, если отклоненный промис встречается раньше. Например:

Тут мы имеем два промиса, где один выполняется через 1 секунду, а другой отклоняется через 1.5 секунды. Как только первый промис выполнен, возвращенный из Promise.race() промис будет иметь статус выполненного не дожидаясь статуса второго промиса.

Здесь data, которая передается в then() является значением первого, выполненного, промиса.

По итогу, Promise.race() дожидается первого промиса и берет его статус как статус возвращаемого промиса.

Комментарий автора перевода: Отсюда собственно и название. Race — гонка

Заключение

Мы узнали, что такое промисы и с чем их едят в JavaScript. Промисы состоят из двух частей 1) Создание промиса и 2) Использование промиса. Большую часть времени вы будете пользоваться промисами, нежели создавать их, но важно знать как они создаются.

Вот и все, надеюсь эта статья оказалась для вас полезной!

Источник

Оцените статью