Оригинальный адрес: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.