Что такое async/await в JavaScript: примеры использования
Паттерн async
/await
используют во многих языках программирования, чтобы выполнять асинхронный код. Асинхронность дает программе возможность производить несколько операций параллельно.
Такой способ написания кода упорядочивает и оптимизирует работу высоконагруженных сайтов, где приходится часто долго ждать обратной связи от программы.
В JavaScript async
и await
создают код на основе промисов (Promise
). Промисы в JavaScript можно сравнить с похожими конструкциями — Future
для Java или Task
для C#. Итак:
- Когда вызывается асинхронная функция в JavaScript, она возвращает промис.
- Когда функция возвращает значение, не являющееся промисом, то промис создается автоматически.
- Если асинхронная функция генерирует исключение, то промис будет отклонен.
Паттерн async
/await
помогает упорядочить код и избавиться от длинных цепочек промисов и функций обратного вызова при написании асинхронного кода. При этом выполнение основных функций программы не прерывается и не тормозится.
Асинхронные функции поддерживаются большинством современных браузеров, поэтому их можно использовать для написания кода везде, за исключением Internet Explorer и Opera Mini.
Функции используются во многих языках (C# 5.0, C ++, Python 3.5, Kotlin 1.1), в в этой статье мы разберем работу async
и await
на примере JavaScript.
Async
Когда мы добавляем к функции слово async
, то она становится асинхронной. То есть она по умолчанию возвращает промис при выполнении кода. Также async
предоставляет дополнительную информацию о том, что функция содержит асинхронное выполнение, а возвращаемое значение будет разрешенным для промиса. Если же функция не может вернуть промис или другое значение, то разрешенное значение будет неопределенным.
Синтаксис async
Асинхронная функция выглядит вот так:
async function name([param[, param[, ...param]]]) { statements }
async
состоит из следующих частей:
name
— название функции;param
— имя аргумента, передаваемого функции;statements
— команды, составляющие тело функции. Сюда также входит элементawait
, о котором мы поговорим чуть позже.
// JavaScript функция с использованием промисов function getNumber1() { return Promise.resolve('374'); } // Функция с использованием async async function getNumber2() { return 374; }
Пример использования async
Давайте рассмотрим на примере, как используется async
:
const movies = [ { title: `A New Hope`}, { title: `The Empire Strikes Back`} ] function getMovies(){ setTimeout(() => { movies.forEach((movie, index) => { console.log(movie.title) }) }, 1000); } function createMovies(movie){ return new Promise((resolve, reject) => { setTimeout(() => { movies.push(movie); const error = false; if(!error){ resolve(); } else{ reject('Error: Something went wrong!') } }, 2000); }) } async function init(){ await createMovies({ title: `Return of the Jedi`}); getMovies(); } int();
Здесь getMovies()
ожидает выполнения createMovies()
в асинхронной функции. То есть createMovies()
— асинхронный элемент, поэтому getMovies()
будет запускаться только после получения ответа от createMovies()
.
Результат выполнения кода:
Ловим ошибки в функциях async
Асинхронные функции и методы не вызывают ошибок. Если вы не используете специальные ключевые слова, то функция всегда будет возвращать промис, неважно — разрешенный или отклоненный.
Чтобы поймать ошибку в коде, нужно использовать элементы try
и catch
. Асинхронная функция, которая сможет определить ошибку и вывести ее на консоль, выглядит вот так:
async function whatever() { try { const valentinogagliardi = new Person("valentinogagliardi"); await valentinogagliardi.getData(); // do stuff with the eventual result and return something } catch (error) { throw Error(error); } } whatever().catch(err => console.error(err));
Давайте запустим выполнение кода и посмотрим, что получилось:
Если не использовать последнюю строку кода console.error(err)
, чтобы отобразить ошибку, то в консоли ничего не появится.
Чтобы поймать исключение, в асинхронной функции нужно прописать try
, catch
и в конце добавить элемент console.error
для отображения ошибок в консоли.
Что такое await
Как мы выяснили, async
делает функцию асинхронной и возращает промисы. А элемент await
ждет результатов выполнения промисов и прописывается в коде перед ними.
Добавление в тело функции await
вводит в приложение синхронное поведение несмотря на то, что функция сама по себе остается асинхронной.
Используя await
, вы сообщаете JavaScript, что выполнение кода займет немного времени и он должен приостановить работу асинхронной функции, пока она не вернет значение промиса. После того, как await
откладывает выполнение асинхронной функции, начинается выполнение последующих операторов. Таким образом освобождается время для выполнения других команд и сохраняется работоспособность запущенного приложения.
Синтаксис await
Как мы уже выяснили, добавление await
к async
позволяет нескольким асинхронным функциям выполняться одновременно. await
также можно использовать самостоятельно в модулях JavaScript, но здесь мы расскажем только про про синтаксис и взаимодействие async
/await
. В коде await
выглядит так:
[rv] = await expression
Где:
expression
— это промис или любое другое значение, чье разрешение должна ждать функция;rv
— возвращает выполненное значение промиса или само значение, если оно не является промисом.
Пришло время посмотреть, как выглядит функция с использованием промисов и асинхронная функция с использованием async
/await
:
// Функция на основе промиса function returnPromises() { return new Promise((resolve) => { setTimeout(() => { console.log("Promise Executed..."); resolve("Sample Data"); }, 3000); }); } //Функция async/await async function ExecuteFunction() { var newData = "Mayank"; var getData = await returnPromises(); console.log(getData); } ExecuteFunction()
ReturnPromise()
в первом случае возвращает промис, разрешение которого нужно ожидать не менее трех секунд. Когда мы вводим асинхронность в код, используя async
/await
, то ключевое слово await
перед вызовом функции принудительно разрешает промис перед дальнейшим выполнением программы. Несмотря на это, задержка выполнения кода также составит три секунды, после чего промис будет разрешен и выполнение кода возобновится.
Фундаментальное различие в поведении кода состоит в том, что при асинхронности может одновременно разрешаться несколько промисов.
При использовании исключительно промисов, как в первом примере, все они будут выполняться последовательно, каждый с задержкой в несколько секунд, что существенно увеличивает время ожидания ответа от программы.
Пример использования await
Рассмотрим пример, где await
ждет разрешения промиса и затем возвращает значение, которое получил:
function resolveAfter2Seconds(x) { return new Promise(resolve => { setTimeout(() => { resolve(x); }, 2000); }); } async function f1() { var x = await resolveAfter2Seconds(10); console.log(x); // 10 } f1();
В консоли результат работы кода будет выглядеть так:
Где нельзя использовать await
Все довольно просто — так как async
/await
идут в связке, то мы не можем использовать вторую часть этого уравнения без первой. То есть await
не будет работать в коде верхнего уровня вне асинхронной функции.
await
может работать самостоятельно, но только с модулями JavaScript. В этом случае await
ждет выполнения программы дочернего модуля, прежде чем запуститься самому. И при этом он не блокирует загрузку других дочерних модулей.
Давайте рассмотрим пример использования await в модуле JavaScript:
// fetch request const colors = fetch('../data/colors.json') .then(response => response.json()); export default await colors;
Коротко об особенностях async/await
- Зачем нужны асинхронные функции? Они необходимы, когда задействовано большое количество итераций или операции внутри цикла являются сложными. Асинхронность позволяет программе выполнять несколько операций параллельно.
- В чем их преимущество перед промисами? В целом, благодаря
async
/await
синтаксис кода становится более чистым, читаемым и понятным. Можно отказаться от бесконечных цепочек промисов и выполнять код быстрее. - Про
async
. Помогает писать синхронно выглядящий код JavaScript, который при этом работает асинхронно. В первую очередьasync
нужен для того, чтобы выполнять несколько задач одновременно. - Про
await
. Используется для ожидания результата от промиса. На данный моментawait
не работает в коде верхнего уровня. Это значит, что когда мы находимся вне асинхронной функции, нельзя использоватьawait
. Исключение — использование элемента внутри модулей JavaScript. - Про исключения. Асинхронные функции не выводят ошибки, как это делают другие элементы кода. Они всегда возвращают промисы, разрешенные или отклоненные. Чтобы перехватить исключение в асинхронной функции, используйте
try
,catch
иconsole.error
.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: