В предыдущей части руководства хорошо видно, что обещания (promises) и использование then
для обработки асинхронных действий легче для понимания, чем пирамида обратных вызовов (callback). ECMAScript 2016 (ES7) предлагает функцию async
и ключевое слово await
.
Асинхронные функции с async
/await
Функция async
позволяет обрабатывать асинхронный код таким образом, чтобы он выглядел синхронным. Функция async
под капотом по-прежнему использует обещания (promise), но имеет более традиционный JavaScript-синтаксис. В этом разделе рассмотрим примеры этого синтаксиса.
Для создания функции async
, достаточно добавить ключевое слово async
перед функцией:
// Асинхронная функция
async function getUser() {
return {}
}
Хотя эта функция ещё не обрабатывает ничего асинхронного, её поведение отличается от традиционной функции. Если вы выполните функцию, вы обнаружите, что она вместо значения возвращает обещание с [[PromiseStatus]]
и [[PromiseValue]]
. Попробуйте залогировать вызов функции getUser
:
console.log(getUser())
Вернётся следующее:
__proto__: Promise
[[PromiseStatus]]: "fulfilled"
[[PromiseValue]]: Object
Это означает, что вы можете обрабатывать функцию async
с помощью then
так же, как и обещание (promise). Попробуйте это с помощью следующего кода:
getUser().then(response => console.log(response))
Такой вызов getUser
передаёт возвращаемое значение анонимной функции, которая записывает значение в консоль. При выполнении этого кода получите следующее:
{}
Функция async
может обрабатывать обещание (promise), вызываемое в ней, с помощью оператора await
. await
может использоваться с функцией async
и, перед выполнением назначенного кода, будет ждать, пока обещание не установится.
Запрос fetch
из предыдущего раздела можно переписать следующим образом с помощью async
/await
:
// Обработка fetch с помощью async/await
async function getUser() {
const response = await fetch('https://api.github.com/users/octocat')
const data = await response.json()
console.log(data)
}
// запуск
getUser()
Здесь оператор await
гарантирует, что данные не попадут в консоль раньше, чем их вернёт асинхронный запрос.
Теперь data
можно обрабатывать внутри функции getUser
без использования then
. Результат, который попадёт в консоль:
login: "octocat",
id: 583231,
avatar_url: "https://avatars3.githubusercontent.com/u/583231?v=4"
blog: "https://github.blog"
company: "@github"
followers: 3203
...
Примечание. Во многих средах режим
async
необходим для использованияawait
, однако некоторые новые версии браузеров и Node разрешают использоватьawait
верхнего уровня, что позволяет обойтись без создания функцииasync
для завершения ожидания.
Наконец, поскольку в асинхронной функции обрабатывается выполненное обещание (promise), можно легко обрабатывать ошибку внутри этой функции. В этом случае вместо использования методов catch
и then
для обработки исключения нужно использовать шаблон try
/catch
. Вот как это выглядит:
// Обработка успеха и ошибок с помощью async/await
async function getUser() {
try {
// Успешно в try
const response = await fetch('https://api.github.com/users/octocat')
const data = await response.json()
console.log(data)
} catch (error) {
// Ошибка в catch
console.error(error)
}
}
Теперь, если вернётся ошибка, будет выполнен код из блока catch
, который запишет эту ошибку в консоль.
Современный асинхронный JavaScript-код легко обрабатывается с помощью синтаксиса async
/await
, но важно иметь практические знания о том, как работают обещания (promise), потому что у них есть дополнительные функции, которые нельзя обработать с помощью async
/await
. Например, объединение обещаний с помощью Promise.all()
.
Итог
Поскольку веб-API часто предоставляют данные асинхронно, изучение того, как обрабатывать результат асинхронных действий, является важной частью работы JavaScript-разработчика. В этой серии статей было рассмотрено, как используется цикл событий для обработки порядка выполнения кода со стеком и очередью. Были рассмотрены три способа обработки успеха или отказа асинхронного события с помощью обратных вызовов (callback), обещаний (promise) и синтаксиса async
/await
. Для обработки асинхронных действий использовался Fetch Web API.
Understanding the Event Loop, Callbacks, Promises, and Async/Await in JavaScript.