Паттерн async
/await
используют во многих языках программирования, чтобы выполнять асинхронный код. Асинхронность дает программе возможность производить несколько операций параллельно.
Такой способ написания кода упорядочивает и оптимизирует работу высоконагруженных сайтов, где приходится часто долго ждать обратной связи от программы.
В JavaScript async
и await
создают код на основе промисов (Promise
). Промисы в JavaScript можно сравнить с похожими конструкциями — Future
для Java или Task
для C#. Итак:
Паттерн async
/await
помогает упорядочить код и избавиться от длинных цепочек промисов и функций обратного вызова при написании асинхронного кода. При этом выполнение основных функций программы не прерывается и не тормозится.
Асинхронные функции поддерживаются большинством современных браузеров, поэтому их можно использовать для написания кода везде, за исключением Internet Explorer и Opera Mini.
Функции используются во многих языках (C# 5.0, C ++, Python 3.5, Kotlin 1.1), в в этой статье мы разберем работу async
и await
на примере JavaScript.
Когда мы добавляем к функции слово 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
:
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()
.
Результат выполнения кода:
Асинхронные функции и методы не вызывают ошибок. Если вы не используете специальные ключевые слова, то функция всегда будет возвращать промис, неважно — разрешенный или отклоненный.
Чтобы поймать ошибку в коде, нужно использовать элементы 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
для отображения ошибок в консоли.
Как мы выяснили, async
делает функцию асинхронной и возращает промисы. А элемент await
ждет результатов выполнения промисов и прописывается в коде перед ними.
Добавление в тело функции await
вводит в приложение синхронное поведение несмотря на то, что функция сама по себе остается асинхронной.
Используя await
, вы сообщаете JavaScript, что выполнение кода займет немного времени и он должен приостановить работу асинхронной функции, пока она не вернет значение промиса. После того, как 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
ждет разрешения промиса и затем возвращает значение, которое получил:
function resolveAfter2Seconds(x) { return new Promise(resolve => { setTimeout(() => { resolve(x); }, 2000); }); } async function f1() { var x = await resolveAfter2Seconds(10); console.log(x); // 10 } f1();
В консоли результат работы кода будет выглядеть так:
Все довольно просто — так как 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
. Помогает писать синхронно выглядящий код JavaScript, который при этом работает асинхронно. В первую очередь async
нужен для того, чтобы выполнять несколько задач одновременно. await
. Используется для ожидания результата от промиса. На данный момент await
не работает в коде верхнего уровня. Это значит, что когда мы находимся вне асинхронной функции, нельзя использовать await
. Исключение — использование элемента внутри модулей JavaScript.try
, catch
и console.error
.Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…
Дедлайн (от англ. deadline — «крайний срок») — это конечная дата стачи проекта или задачи…