Рубріки: ОсновыТеория

Что такое 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

О том, как работает асинхронная функция в одной картинке / scoutapm.com

  • Зачем нужны асинхронные функции? Они необходимы, когда задействовано большое количество итераций или операции внутри цикла являются сложными. Асинхронность позволяет программе выполнять несколько операций параллельно.
  • В чем их преимущество перед промисами? В целом, благодаря async/await синтаксис кода становится более чистым, читаемым и понятным. Можно отказаться от бесконечных цепочек промисов и выполнять код быстрее.
  • Про async. Помогает писать синхронно выглядящий код JavaScript, который при этом работает асинхронно. В первую очередь async нужен для того, чтобы выполнять несколько задач одновременно.
  • Про await. Используется для ожидания результата от промиса. На данный момент await не работает в коде верхнего уровня. Это значит, что когда мы находимся вне асинхронной функции, нельзя использовать await. Исключение — использование элемента внутри модулей JavaScript.
  • Про исключения. Асинхронные функции не выводят ошибки, как это делают другие элементы кода. Они всегда возвращают промисы, разрешенные или отклоненные. Чтобы перехватить исключение в асинхронной функции, используйте try, catch и console.error.

Останні статті

Обучение Power BI – какие онлайн курсы аналитики выбрать

Сегодня мы поговорим о том, как выбрать лучшие курсы Power BI в Украине, особенно для…

13.01.2024

Work.ua назвал самые конкурентные вакансии в IТ за 2023 год

В 2023 году во всех крупнейших регионах конкуренция за вакансию выросла на 5–12%. Не исключением…

08.12.2023

Украинская IT-рекрутерка создала бесплатный трекер поиска работы

Unicorn Hunter/Talent Manager Лина Калиш создала бесплатный трекер поиска работы в Notion, систематизирующий все этапы…

07.12.2023

Mate academy отправит работников в 10-дневный оплачиваемый отпуск

Edtech-стартап Mate academy принял решение отправить своих работников в десятидневный отпуск – с 25 декабря…

07.12.2023

Переписки, фото, история браузера: киевский программист зарабатывал на шпионаже

Служба безопасности Украины задержала в Киеве 46-летнего программиста, который за деньги устанавливал шпионские программы и…

07.12.2023

Как вырасти до сеньйора? Девелопер создал популярную подборку на Github

IT-специалист Джордан Катлер создал и выложил на Github подборку разнообразных ресурсов, которые помогут достичь уровня…

07.12.2023