Async/await
Существует специальный синтаксис для работы с промисами, который называется «async/await». Он удивительно прост для понимания и использования.
Асинхронные функции
У слова async один простой смысл: эта функция всегда возвращает промис. Значения других типов оборачиваются в завершившийся успешно промис автоматически.
Например, эта функция возвратит выполненный промис с результатом 1 :
Можно и явно вернуть промис, результат будет одинаковым:
Await
Ключевое слово await заставит интерпретатор JavaScript ждать до тех пор, пока промис справа от await не выполнится. После чего оно вернёт его результат, и выполнение кода продолжится.
В этом примере промис успешно выполнится через 1 секунду:
В данном примере выполнение функции остановится на строке (*) до тех пор, пока промис не выполнится. Это произойдёт через секунду после запуска функции. После чего в переменную result будет записан результат выполнения промиса, и браузер отобразит alert-окно «готово!».
Обратите внимание, хотя await и заставляет JavaScript дожидаться выполнения промиса, это не отнимает ресурсов процессора. Пока промис не выполнится, JS-движок может заниматься другими задачами: выполнять прочие скрипты, обрабатывать события и т.п.
Ошибки не будет, если мы укажем ключевое слово async перед объявлением функции. Как было сказано раньше, await можно использовать только внутри async –функций.
Давайте перепишем пример showAvatar() из раздела Цепочка промисов с помощью async/await :
Получилось очень просто и читаемо, правда? Гораздо лучше, чем раньше.
Можно обернуть этот код в анонимную async –функцию, тогда всё заработает:
В примере ниже, экземпляры класса Thenable будут работать вместе с await :
Для объявления асинхронного метода достаточно написать async перед именем:
Обработка ошибок
Делает то же самое, что и такой:
Но есть отличие: на практике промис может завершиться с ошибкой не сразу, а через некоторое время. В этом случае будет задержка, а затем await выбросит исключение.
Так сделано в строке (*) в примере выше.
Итого
Ключевое слово async перед объявлением функции:
Ключевое слово await перед промисом заставит JavaScript дождаться его выполнения, после чего:
Вместе они предоставляют отличный каркас для написания асинхронного кода. Такой код легко и писать, и читать.
Поймут даже дети: простое объяснение async/await и промисов в JavaScript
Привет, Хабр! Представляю вашему вниманию перевод статьи «JavaScript Async/Await and Promises: Explained like you’re five years old» автора Jack Pordi.
Каждый, кто считает себя JavaScript-разработчиком, в какой-то момент должен был столкнуться с callback-функциями, промисами или, с недавних пор, с синтаксисом async/await. Если вы пробыли в игре достаточно долго, вы, вероятно, застали времена, когда вложенные callback-функции были единственным способом достижения асинхронности в JavaScript.
Когда я начал изучать и писать на JavaScript, уже существовало миллиард руководств и туториалов, объясняющих, как добиться асинхронности в JavaScript. Тем не менее, многие из них просто объясняли, как преобразовать callback-функции в промисы или промисы в async/await. Для многих этого, вероятно, более чем достаточно, чтобы они «поладили» с ними и начали использовать их в своем коде.
Однако если вы, как я, действительно хотите понять асинхронное программирование (а не только синтаксис JavaScript!), то, возможно, вы согласитесь со мной, что существует нехватка материалов, объясняющих асинхронное программирование фактически с нуля.
Что значит «асинхронный»?
Как правило, задавая этот вопрос, вы можете услышать что-то из следующего:
Пример из жизни
Представьте, что вы готовите овощной суп. Для хорошей и простой аналогии предположим, что овощной суп состоит только из лука и моркови. Рецепт такого супа может быть следующим:
Теперь давайте перейдем к JavaScript, хорошо?
Итак, придерживаясь того же примера овощного супа, я напишу несколько функций для представления шагов рецепта, описанных выше.
Сначала давайте напишем синхронные функции, которые представляют задачи, не требующие ожидания времени. Это старые добрые функции JavaScript, но обратите внимание, что я описал функции chopCarrots и chopOnions как задачи, требующие активной работы (и времени), позволяя им выполнять некоторые длинные вычисления. Полный код доступен в конце статьи [1].
Перед тем, как перейти к асинхронным функциям, сначала я быстро объясню, как система типов JavaScript обрабатывает асинхронность: в основном все результаты (включая ошибки) асинхронных операций должны быть обернуты в промис(ы).
Чтобы функция возвращала промис, вы можете:
Итак, наши асинхронные функции, представляющие шаги 3–5 приготовления овощного супа, выглядят следующим образом:
Ещё раз, я удалил детали реализации, чтобы на них не отвлекаться, но они опубликованы в конце статьи [1].
Важно знать, что для того, чтобы дождаться результата промиса, чтобы потом можно было с ним что-то делать, вы можете просто использовать ключевое слово await :
Итак, теперь нам просто нужно собрать все это вместе:
Следовательно, мы просто добавляем ключевое слово async в функцию makeSoup :
В контексте функции makeSoup вы можете просто думать о ней как о том, что вы ожидаете, что что-то произойдет (или результат, который в конечном итоге будет возвращен).
Но помните: вы (как и ваш процессор) никогда не захотите просто сидеть и ждать чего-то, в то время как можно потратить свое время на другие дела.
Следовательно, вместо того, чтобы только готовить суп, мы могли бы параллельно готовить что-то еще:
Видите? Синтаксис async/await на самом деле довольно прост в использовании, если вы его понимаете, согласны?
Что насчет явных промисов?
Хорошо, если вы настаиваете, я перейду к использованию явных промисов (прим. перев.: под явными промисами автор подразумевает непосредственно сам синтаксис промисов, а под неявными промисами – синтаксис async/await, т.к. он возвращает промис неявно – не нужно писать return new Promise(…) ). Имейте в виду, что методы async/await основаны на самих промисах и, следовательно, оба варианта полностью совместимы.
Явные промисы, на мой взгляд, находятся между callback-функциями старого стиля и новым сексуальным синтаксисом async/await. В качестве альтернативы, вы также можете думать о сексуальном синтаксисе async/await как о не более чем неявных промисах. В конце концов, конструкция async/await пришла после промисов, которые, в свою очередь, пришли после callback-функций.
Воспользуйтесь нашей машиной времени, чтобы переместиться в «ад обратных вызовов» (callback hell) [4]:
Я не собираюсь лгать, я написал этот пример на лету, когда работал над этой статьей, и это заняло у меня гораздо больше времени, чем я хотел бы признать. Многие из вас, возможно, даже не будут знать, что вообще тут происходит. Мой дорогой друг, разве все эти callback-функции не ужасны? Пусть это будет уроком, чтобы никогда больше не использовать callback-функции.
И, как и обещал, тот же пример с явными промисами:
Как видите, промисы все еще похожи на callback-функции.
Я не буду вдаваться в подробности, но главное:
Заключение
Я надеюсь, что вы получили некоторое представление о промисах и асинхронном программировании из этой статьи или, возможно, хотя бы узнали о хорошем примере из жизни, чтобы объяснить это кому-то еще.
Итак, какой из способов вам использовать: промисы или async/await?
Ответ полностью зависит от вас — и я бы сказал, что совмещать их не так уж и плохо, так как оба подхода полностью совместимы друг с другом.
Тем не менее, лично я нахожусь на 100% в лагере async/await, так как для меня код намного понятнее и лучше отражает истинную многозадачность асинхронного программирования.
Конструкция async/await в JavaScript: сильные стороны, подводные камни и особенности использования
Конструкция async/await появилась в стандарте ES7. Её можно считать замечательным улучшением в сфере асинхронного программирования на JavaScript. Она позволяет писать код, который выглядит как синхронный, но используется для решения асинхронных задач и не блокирует главный поток. Несмотря на то, что async/await — это отличная новая возможность языка, пользоваться ей правильно не так уж и просто. Материал, перевод которого мы публикуем сегодня, посвящён разностороннему исследованию async/await и рассказу о том, как использовать этот механизм правильно и эффективно.
Сильные стороны async/await
Самое важное преимущество, которое получает программист, пользующийся конструкцией async/await, заключается в том, что она даёт возможность писать асинхронный код в стиле, характерном для синхронного кода. Сравним код, написанный с использованием async/await, и код, основанный на промисах.
Привлекательность async/await обеспечивается не только улучшением читабельности кода. Этот механизм, кроме того, пользуется отличной поддержкой браузеров, не требующей каких-либо обходных путей. Так, на сегодняшний день асинхронные функции полностью поддерживают все основные браузеры.
Все основные браузеры поддерживают асинхронные функции (caniuse.com)
Такой уровень поддержки означает, например, что код, использующий async/await, не нужно транспилировать. Кроме того, это облегчает отладку, что, пожалуй, даже более важно, чем отсутствие необходимости в транспиляции.
Отладка асинхронной функции. Отладчик дождётся выполнения await-строки и перейдёт на следующую строку после завершения операции
О неправильном восприятии async/await
В некоторых публикациях конструкцию async/await сравнивают с промисами и говорят о том, что она представляет собой новое поколении эволюции асинхронного программирования на JavaScript. С этим я, при всём уважении к авторам таких публикаций, позволю себе не согласиться. Async/await — это улучшение, но это — не более чем «синтаксический сахар», появление которого не ведёт к полному изменению стиля программирования.
В сущности, асинхронные функции — это промисы. Перед тем, как программист сможет правильно использовать конструкцию async/await, он должен хорошо изучить промисы. Кроме того, в большинстве случаев, работая с асинхронными функциями, нужно использовать и промисы.
Взгляните на функции getBooksByAuthorWithAwait() и getBooksByAuthorWithPromises() из вышеприведённого примера. Обратите внимание на то, что они идентичны не только в плане функционала. У них ещё и совершенно одинаковые интерфейсы.
На самом деле, суть проблемы, о которой мы тут говорим, заключается в неправильном восприятии новой конструкции, когда создаётся обманчивое ощущение того, что синхронную функцию можно конвертировать в асинхронную благодаря простому использованию ключевых слов async и await и ни о чём больше не задумываться.
Подводные камни async/await
Поговорим о наиболее распространённых ошибках, которые можно сделать, пользуясь async/await. В частности — о нерациональном использовании последовательных вызовов асинхронных функций.
Хотя ключевое слово await может сделать код похожим на синхронный, пользуясь им, стоит помнить о том, что код это асинхронный, а значит, надо очень внимательно относиться к последовательным вызовом асинхронных функций.
Этот код, с точки зрения логики, кажется правильным. Однако тут имеется серьёзная проблема. Вот как он работает.
Вот правильный подход к написанию такого кода:
Рассмотрим ещё один пример неправильного использования асинхронных функций. Тут всё ещё хуже, чем в предыдущем примере. Как видите, для того, чтобы асинхронно загрузить список неких элементов, нам надо полагаться на возможности промисов.
Обработка ошибок
▍Конструкция try/catch
Стандартным способом для обработки ошибок при использовании async/await является конструкция try/catch. Я рекомендую пользоваться именно этим подходом. При выполнении await-вызова значение, выдаваемое при отклонении промиса, представляется в виде исключения. Вот пример:
Ошибка, перехваченная в блоке catch — это как раз и есть значение, получающееся при отклонении промиса. После перехвата исключения мы можем применить несколько подходов для работы с ним:
▍Возврат функциями двух значений
Источником вдохновения для следующего способа обработки ошибок в асинхронном коде стал язык Go. Он позволяет асинхронным функциям возвращать и ошибку, и результат. Подробнее об этом можно почитать здесь.
Если в двух словах, то асинхронные функции, при таком подходе, можно использовать так:
Лично мне это не нравится, так как этот способ обработки ошибок привносит в JavaScript стиль программирования на Go, что выглядит неестественно, хотя, в некоторых случаях, это может оказаться весьма полезным.
Для этого подхода характерны две небольших проблемы:
Итоги
Конструкция async/await, которая появилась в ES7, определённо, является улучшением механизмов асинхронного программирования в JavaScript. Она способна облегчить чтение и отладку кода. Однако, для того, чтобы пользоваться async/await правильно, необходимо глубокое понимание промисов, так как async/await — это всего лишь «синтаксический сахар», в основе которого лежат промисы.
Надеемся, этот материал позволил вам ближе познакомиться с async/await, и то, что вы тут узнали, убережёт вас от некоторых распространённых ошибок, возникающих при использовании этой конструкции.
Уважаемые читатели! Пользуетесь ли вы конструкцией async/await в JavaScript? Если да — просим рассказать о том, как вы обрабатываете ошибки в асинхронном коде.
Разбираем Async/Await в JavaScript на примерах
Автор статьи разбирает на примерах Async/Await в JavaScript. В целом, Async/Await — удобный способ написания асинхронного кода. До появления этой возможности подобный код писали с использованием коллбэков и промисов. Автор оригинальной статьи раскрывает преимущества Async/Await, разбирая различные примеры.
Напоминаем: для всех читателей «Хабра» — скидка 10 000 рублей при записи на любой курс Skillbox по промокоду «Хабр».
Skillbox рекомендует: Образовательный онлайн-курс «Java-разработчик».
Callback
Callback представляет собой функцию, вызов которой отложен на неопределенное время. Раньше обратные вызовы использовались в тех участках кода, где результат не мог быть получен сразу.
Вот пример асинхронного чтения файла на Node.js:
Проблемы возникают в тот момент, когда требуется выполнить сразу несколько асинхронных операций. Давайте представим себе вот такой сценарий: выполняется запрос в БД пользователя Arfat, нужно считать его поле profile_img_url и загрузить картинку с сервера someserver.com.
После загрузки конвертируем изображение в иной формат, например из PNG в JPEG. Если конвертация прошла успешно, на почту пользователя отправляется письмо. Далее информация о событии заносится в файл transformations.log с указанием даты.
Стоит обратить внимание на наложенность обратных вызовов и большое количество >) в финальной части кода. Это называется Callback Hell или Pyramid of Doom.
Недостатки такого способа очевидны:
Положительным моментом промисов стало то, что с ними код читается гораздо лучше, причем сверху вниз, а не слева направо. Тем не менее у промисов тоже есть свои проблемы:
Предположим, что есть цикл for, выводящий последовательность чисел от 0 до 10 со случайным интервалом (0–n секунд). Используя промисы, нужно изменить этот цикл таким образом, чтобы числа выводились в последовательности от 0 до 10. Так, если вывод нуля занимает 6 секунд, а единицы — 2 секунды, сначала должен быть выведен ноль, а потом уже начнется отсчет вывода единицы.
Async-функции
Добавление async-функций в ES2017 (ES8) упростило задачу работы с промисами. Отмечу, что async-функции работают «поверх» промисов. Эти функции не представляют собой качественно другие концепции. Async-функции задумывались как альтернатива коду, который использует промисы.
Async/Await дает возможность организовать работу с асинхронным кодом в синхронном стиле.
Таким образом, знание промисов облегчает понимание принципов Async/Await.
В обычной ситуации он состоит из двух ключевых слов: async и await. Первое слово и превращает функцию в асинхронную. В таких функциях разрешается использование await. В любом другом случае использование этой функции вызовет ошибку.
Async вставляется в самом начале объявления функции, а в случае использования стрелочной функции — между знаком «=» и скобками.
Эти функции можно поместить в объект в качестве методов либо же использовать в объявлении класса.
NB! Стоит помнить, что конструкторы класса и геттеры/сеттеры не могут быть асинхронными.
Семантика и правила выполнения
Async-функции, в принципе, похожи на стандартные JS-функции, но есть и исключения.
Так, async-функции всегда возвращают промисы:
В частности, fn возвращает строку hello. Ну а поскольку это асинхронная функция, то значение строки обертывается в промис при помощи конструктора.
Вот альтернативная конструкция без Async:
В этом случае возвращение промиса производится «вручную». Асинхронная функция всегда обертывается в новый промис.
В том случае, если возвращаемое значение — примитив, async-функция выполняет возврат значения, обертывая его в промис. В том случае, если возвращаемое значение и есть объект промиса, его решение возвращается в новом промисе.
Но что произойдет в том случае, если внутри асинхронной функции окажется ошибка?
Если она не будет обработана, foo() вернет промис с реджектом. В этой ситуации вместо Promise.resolve вернется Promise.reject, содержащий ошибку.
Async-функции на выходе всегда дают промис, вне зависимости от того, что возвращается.
Await влияет на выражения. Так, если выражение является промисом, async-функция приостанавливается до момента выполнения промиса. В том случае, если выражение не является промисом, оно конвертируется в промис через Promise.resolve и потом завершается.
А вот описание того, как работает fn-функция.
Решаем задачу
Ну а теперь давайте рассмотрим решение задачи, которая была указана выше.
Вот решение с выводом чисел, здесь есть два варианта.
А вот решение с использованием async-функций.
Необработанные ошибки обертываются в rejected промис. Тем не менее в async-функциях можно использовать конструкцию try/catch для того, чтобы выполнить синхронную обработку ошибок.
canRejectOrReturn() — это асинхронная функция, которая либо удачно выполняется (“perfect number”), либо неудачно завершается с ошибкой (“Sorry, number too big”).
Поскольку в примере выше ожидается выполнение canRejectOrReturn, то собственное неудачное завершение повлечет за собой исполнение блока catch. В результате функция foo завершится либо с undefined (когда в блоке try ничего не возвращается), либо с error caught. В итоге у этой функции не будет неудачного завершения, поскольку try/catch займется обработкой самой функции foo.
Стоит уделить внимание тому, что в примере из foo возвращается canRejectOrReturn. Foo в этом случае завершается либо perfect number, либо возвращается ошибка Error (“Sorry, number too big”). Блок catch никогда не будет исполняться.
Проблема в том, что foo возвращает промис, переданный от canRejectOrReturn. Поэтому решение функции foo становится решением для canRejectOrReturn. В этом случае код будет состоять всего из двух строк:
А вот что будет, если использовать вместе await и return:
В коде выше foo удачно завершится как с perfect number, так и с error caught. Здесь отказов не будет. Но foo завершится с canRejectOrReturn, а не с undefined. Давайте убедимся в этом, убрав строку return await canRejectOrReturn():
Распространенные ошибки и подводные камни
В некоторых случаях использование Async/Await может приводить к ошибкам.
Такое случается достаточно часто — перед промисом забывается ключевое слово await:
В коде, как видно, нет ни await, ни return. Поэтому foo всегда завершается с undefined без задержки в 1 секунду. Но промис будет выполняться. Если же он выдает ошибку или реджект, то в этом случае будет вызываться UnhandledPromiseRejectionWarning.
Async-функции в обратных вызовах
Нам нужны аккаунты ArfatSalman, octocat, norvig. В этом случае выполняем:
Чрезмерно последовательное использование await
В качестве примера возьмем такой код:
Здесь в переменную count помещается число репо, затем это число добавляется в массив counts. Проблема кода в том, что пока с сервера не придут данные первого пользователя, все последующие пользователи будут находиться в режиме ожидания. Таким образом, в единый момент обрабатывается лишь один пользователь.
Promise.all на входе получает массив промисов с возвращением промиса. Последний после завершения всех промисов в массиве или при первом реджекте завершается. Может случиться так, что все они не запустятся одновременно, — для того чтобы обеспечить одновременный запуск, можно использовать p-map.
Заключение
Async-функции становятся все более важными для разработки. Ну а для адаптивного использования async-функций стоит воспользоваться Async Iterators. JavaScript-разработчик должен хорошо разбираться в этом.
Асинхронное программирование с async/await
Доброго времени суток, друзья!
Сравнительно новыми дополнениями JavaScript являются асинхронные функции и ключевое слово await. Эти возможности в основном являются синтаксическим сахаром над обещаниями (промисами), облегчая написание и чтение асинхронного кода. Они делают асинхронный код похожим на синхронный. Данная статья поможет вам разобраться, что к чему.
Условия: базовая компьютерная грамотность, знание основ JS, понимание азов асинхронного кода и обещаний.
Цель: понять, как устроены обещания, и как они используются.
Основы async/await
Использование async/await состоит из двух частей.
Ключевое слово async
Прежде всего, у нас есть ключевое слово async, которое мы помещаем перед объявлением функции, чтобы сделать ее асинхронной. Асинхронная функция — это функция, которая предвосхищает возможность использования ключевого слова await для запуска асинхронного кода.
Попробуйте набрать в консоли браузера следующее:
Функция вернет ‘Hello’. Ничего необычно, верно?
Но что если мы превратим ее в асинхронную функцию? Попробуйте сделать следующее:
Теперь вызов функции возвращает обещание. Это одна из особенностей асинхронных функций — они возвращают значения, которые гарантировано преобразуются в обещания.
Вы также можете создать асинхронное функциональное выражения, например, так:
Также можно использовать стрелочные функции:
Все эти функции делают одно и тоже.
Таким образом, добавление ключевого слова async заставляет функцию возвращать обещание вместо значения. Кроме того, это позволяет синхронным функциям избегать любых накладных расходов, связанных с запуском и поддержкой использования await. Простое добавление async перед функцией обеспечивает автоматическую оптимизацию кода движком JS. Круто!
Ключевое слово await
Преимущества асинхронных функций становятся еще более очевидными, когда вы комбинируете их с ключевым словом await. Оно может быть добавлено перед любой основанной на обещаниях функцией, чтобы заставить ее дожидаться завершения обещания, а затем вернуть результат. После этого выполняется следующий блок кода.
Вы можете использовать await при вызове любой функции, возвращающей обещание, включая функции Web API.
Вот тривиальный пример:
Разумеется, приведенный код бесполезен, он лишь служит демонстрацией синтаксиса. Давайте двигаться дальше и посмотрим на реальный пример.
Переписываем код на обещаниях с использованием async/await
Возьмем пример с fetch из предыдущей статьи:
У вас уже должны быть понимание того, что такое обещания и как они работают, но давайте перепишем этот код с использованием async/await, чтобы увидеть насколько все стало проще:
Использование ключевого слова async превращает функцию в обещание, поэтому мы можем использовать смешанный подход из обещаний и await, выделив вторую часть функции в отдельный блок с целью повышения гибкости:
Вы можете переписать пример или запустить наше живое демо (см. также исходный код).
Но как это работает?
Мы обернули код внутри функции и добавили ключевое слово async перед ключевым словом function. Вам нужно создать асинхронную функцию, чтобы определить блок кода, в котором будет запускаться асинхронный код; await работает только внутри асинхронных функций.
Еще раз: await работает только в асинхронных функциях.
Значение, возвращаемое обещанием fetch(), присваивается переменной response, когда данное значение становится доступным, и «парсер» останавливается на этой линии до завершения обещания. Как только значение становится доступным, парсер переходит к следующей строчке кода, которая создает Blob. Эта строчка также вызывает основанный на обещаниях асинхронный метод, поэтому здесь мы также используем await. Когда результат операции возвращается, мы возвращаем его из функции myFetch().
Добавляем обработку ошибок
Если вы хотите добавить обработку ошибок, у вас есть несколько вариантов.
Вы можете использовать синхронную структуру try. catch вместе с async/await. Этот пример является расширенной версией приведенного выше кода:
Блок catch()<> принимает объект ошибки, который мы назвали «e»; теперь мы можем вывести его в консоль, это позволит нам получить сообщение о том, в каком месте кода произошла ошибка.
Ожидание Promise.all()
Async/await основан на обещаниях, так что вы можете использовать все возможности последних. К ним, в частности, относится Promise.all() — вы легко можете добавить await к Promise.all(), чтобы записать все возвращаемые значения способом, похожим на синхронный код. Снова возьмем пример из предыдущей статьи. Держите вкладку с ним открытой, чтобы сравнить с показанным ниже кодом.
С async/await (см. живое демо и исходный код) он выглядит так:
Мы легко превратили функцию fetchAndDecode() в асинхронную с помощью парочки изменений. Обратите внимания на строчку:
Недостатки async/await
Async/await имеет парочку недостатков.
Async/await делает код похожим на синхронный и в некотором смысле заставляет его вести себя более синхронно. Ключевое слово await блокирует выполнение следующего за ним кода до завершения обещания, как это происходит в синхронной операции. Это позволяет выполняться другим задачам, но ваш собственный код является заблокированным.
Это означает, что ваш код может быть замедлен большим количеством ожидающих обещаний, следующих друг за другом. Каждый await будет ждать завершения предыдущего, в то время как мы хотели бы, чтобы обещания начали выполняться одновременно, так будто мы не используем async/await.
Существует шаблон проектирования, позволяющий смягчить эту проблему — отключение всех процессов обещаний путем сохранения объектов Promise в переменных и последующего их ожидания. Давайте посмотрим на то, как это реализуется.
В нашем распоряжении имеется два примера — slow-async-await.html (см. исходный код) и fast-async-await.html (см. исходный код). Оба примера начинаются с функции-обещания, которая имитирует асинхронную операцию с помощью setTimeout():
Затем следует асинхронная функция timeTest(), которая ожидает трех вызовов timeoutPromise():
Каждый из трех вызовов timeTest() завершается записью времени выполнения обещания, затем записывается время выполнения всей операции:
В каждом случае функция timeTest() отличается.
В slow-async-await.html timeTest() выглядит так:
Здесь мы просто ожидаем три вызова timeoutPromise, каждый раз устанавливая задержку в 3 секунды. Каждый вызов ждет завершения предыдущего — если вы запустите первый пример, то увидите модальное окно примерно через 9 секунд.
В fast-async-await.html timeTest() выглядит так:
Здесь мы сохраняем три объекта Promise в переменных, что заставляет связанные с ним процессы выполняться одновременно.
Далее мы ожидаем их результаты — поскольку обещания начинают выполняться одновременно, обещания завершатся также в одно время; когда вы запустите второй пример, то увидите модальное окно примерно через 3 секунды!
Вам следует осторожно тестировать код и помнить об этом при снижении производительности.
Еще одним незначительным неудобством является необходимость оборачивания ожидаемых обещаний в асинхронную функцию.
Использование async/await совместно с классами
В завершение отметим, что вы можете добавлять async даже в методах создания классов, чтобы они возвращали обещания, и ждать обещания внутри них. Возьмем код из статьи про объектно-ориентированный JS и сравним его с модифицированной с помощью async версией:
Метод класса может быть использован следующим образом:
Поддержка браузеров
Одним из препятствий использования async/await является отсутствие поддержки старых браузеров. Эта возможность доступна почти во всех современных браузерах, также как обещания; некоторые проблемы существуют в Internet Explorer и Opera Mini.
Если вы хотите использовать async/await, но нуждаетесь в поддержке старых браузеров, можете использовать библиотеку BabelJS — она позволяет использовать новейший JS, преобразуя его в подходящий для конкретного браузера.
Заключение
Async/await позволяет писать асинхронный код, который легко читать и поддерживать. Несмотря на то, что async/await поддерживается хуже других способов написания асинхронного кода, его определенно стоит изучить.






