Оригинальный адрес:JavaScript async/await: The Good Part, Pitfalls and How to Use
ES7 по введениюasync/await
Значительно улучшает асинхронное программирование в JavaScript. Он предоставляет способ использования асинхронного доступа в стиле синхронного кода.resoruces
образом, не блокируя основной поток. Однако использовать его немного сложно. В этой статье мы рассмотрим с разных точек зренияasync/await
, и покажет, как правильно и эффективно их использовать.
Преимущества async/await
async/await
Наиболее важным преимуществом, которое он нам дает, является синхронный стиль программирования. Давайте посмотрим на пример.
async/await
соотношение версийpromise
Версии легче понять. если игнорироватьawait
ключевое слово, код выглядит точно так же, как любой другой синхронный язык, такой как Python.
Хорошая сторона заключается не только в читабельности,async/await
Есть встроенная поддержка браузера. На сегодняшний день все основные браузерыПроверитьОба полностью поддерживают асинхронные функции.
Встроенная поддержка означает, что вам не нужно преобразовывать код. Что еще более важно, это помогает при отладке. Когда вы устанавливаете точку останова на входе в функцию и пропускаетеawait
строку, вы увидите отладчик вbookModel.fetchAll()
Сделайте небольшую паузу во время выполнения, затем перейдите к следующей строке..filter
! это лучше, чемpromise
Ситуация намного проще, т.promise
случае вы должны быть в.filter
строку, чтобы установить другую точку останова.
async
ключевые слова. ГоворитсяgetBooksByAuthorWithAwait()
Возвращаемое значение функции гарантированно будетpromise
, так что вызывающий абонент может безопасно позвонитьgetBooksByAuthorWithAwait().then(...)
илиawait getBooksByAuthorWithAwait()
. Взгляните на код ниже (плохая практика!):
В приведенном выше кодеgetBooksByAuthorWithPromise
может вернутьpromise
(нормальный) илиnull
значение (исключение), и в этом случае вызывающая сторона не может безопасно вызвать.then()
. пройти черезasync
заявление, это возвращаетnull
ситуация будет невозможна.
Async/await может ввести в заблуждение
Некоторые статьи будутasync/await
а такжеPromise
Сравнивая его и утверждая, что это следующее поколение в эволюции асинхронного программирования JavaScript, я не согласен.Async/await
Это улучшение, но это просто синтаксис, который не полностью изменит наш стиль программирования.
По сути,await
функция по-прежнемуpromise
. при правильном использованииawait
функция, вы должны пониматьpromises
, и что в большинстве случаев вам нужно использовать обаpromises
и асинхронные функции.
Рассмотрим пример вышеgetBooksByAuthorWithAwait()
а такжеgetBooksByAuthorWithPromises()
функция. Обратите внимание, что они не только функционально одинаковы, но и имеют точно такой же интерфейс.
Если вы позвоните напрямуюgetBooksByAuthorWithAwait()
, что означает, что он вернетpromise
.
Что ж, это неплохо. Толькоawait
Название звучит как «о, это может превратить асинхронную функцию в функцию синхронизации», что на самом деле неверно.
Яма Async/await
затем используйтеasync/await
какая ошибка возникает? Вот несколько распространенных ситуаций.
слишком последовательный
несмотря на то чтоawait
Можно сделать так, чтобы ваш код выглядел синхронным, но имейте в виду, что он по-прежнему асинхронный, и необходимо соблюдать осторожность, чтобы не быть слишком последовательным.
-
await bookModel.fetchAll()
будет ждать, покаfetchAll()
вернуть. - потом
await authorModel.fetch(authorId)
будет называться.осторожность,authorModel.fetch(authorId)
это не зависит отbookModel.fetchAll()
, их действительно можно вызывать параллельно! Однако, поawait
При использовании здесь два вызова становятся последовательными, и общее время выполнения будет намного больше, чем в параллельной версии.
Это правильный путь:
Или, что еще хуже, если вы хотите получить элементы списка один за другим, вам придется полагаться наpromise
:Проще говоря, вам все равно нужно думать о рабочем процессе асинхронно, а затем пытаться писать код синхронно.await
. В сложных рабочих процессах используйте напрямуюpromises
Может быть проще.
обработка ошибок
использоватьpromises
, асинхронная функция имеет два возможных возвращаемых значения: разрешенное значение и отклоненное значение. мы можем.then()
для нормальных условий,.catch()
для особых случаев. но,async/await
Обработка ошибок может быть сложной.
Попробуйте поймать
Самый стандартный (и то, что я рекомендую) способ - использоватьtry...catch
утверждение. когдаawait
При вызове любое отклоненное значение будет выброшено как исключение. Вот пример:
catch
Ошибка - это именно отклоненное значение. После того, как мы нашли исключение, есть несколько способов его обработки:
- Обрабатывать исключения и возвращать нормальные значения. (не в
catch
заблокировать с помощью любогоreturn
оператор, который эквивалентен использованиюreturn undefined
, также является нормальным значением. ) - Бросьте его, если вы хотите, чтобы вызывающий абонент обработал его. Может генерировать обычный объект ошибки напрямую
throw error
, который вpromise
разрешено в цепочкеasync getBooksByAuthorWithAwait()
функция (т.е. ее все еще можно вызывать такgetBooksByAuthorWithAwait().then(...).catch(error => ...)
); или вы можете использоватьError
Ошибки переноса объектов, например.throw new Error(error)
, предоставит полную трассировку стека, когда эта ошибка отображается в консоли. - отказаться от него, как
return Promise.reject(error)
. Это эквивалентноthrow error
Не рекомендуется.
Преимущество использования try...catch заключается в том,:
- Просто, традиционный. Пока у вас есть опыт работы с другими языками, такими как Java или C ++, у вас не должно быть никаких трудностей.
- Если вам не нужно выполнять обработку ошибок на каждом этапе, вы все равно можете
try...catch
Оберните несколько в блокawait
Вызывается для обработки ошибок в одном месте.
В этом подходе тоже есть недостаток. из-заtry...catch
будет перехватывать каждое исключение в блоке, поэтому будет перехватывать некоторые исключения, которые обычно неpromises
пойманное исключение. Рассмотрим этот пример:
ReferenceError: cb is not defined
ошибка. ошибка вызванаconsole.log()
вывод вместо самого JavaScript. Иногда это может быть фатальным. еслиBookModel
Будучи глубоко запутанным в цепочке вызовов функций, и один из этих вызовов поглощает ошибку, было бы очень сложно найти такую неопределенную ошибку.
заставить функцию возвращать два значения
Другой способ обработки ошибок вдохновлен языком Go. Это позволяет асинхронным функциям возвращать ошибки и результаты. Подробнее см. в этом сообщении в блоге:How to write async await without try-catch blocks in Javascript
Короче говоря, вы можете использовать что-то вроде этогоawait
функция:
использовать .поймать
Последний метод, который мы здесь рассмотрим, — это использовать.catch()
.
передуматьawait
Функция: он будет ждатьpromise
完成其工作。 Отзывать,promise.catch()
также будетpromise
, поэтому мы можем написать обработку ошибок следующим образом:
- это
promises
а такжеawait
Смесь функций. тебе еще нужно знатьpromises
Принцип работы. - Обработка ошибок происходит до нормального пути, который не интуитивно понятен.
В заключение
Ключевые слова, представленные в ES7async/await
Определенно улучшение по сравнению с асинхронным программированием в JavaScript. Это может упростить чтение и отладку кода. Однако для того, чтобы правильно их использовать, их необходимо полностью понять.promise
, так как они представляют собой не что иное, как синтаксический сахар, в то время как лежащая в основе техника все ещеpromise
.