Поиск по сайту:

Как работает Async/Await?


Несмотря на все причудливые функции, встроенные в современные языки программирования, внутри они все еще довольно примитивны. Без асинхронного программирования длительные вызовы внешних служб прерывали бы выполнение программы. Async/await решает эту проблему.

Зачем использовать Async/Await?

Большинство программ используют один основной поток и выполняют инструкции ЦП последовательно, но, что более важно, синхронно. Если вам нужно извлечь значение из памяти, вы на некоторое время застряли в IOWait, ожидая, пока ваша оперативная память освободится. вернуть ответ. Если вам нужно получить значение с диска, вы можете застрять на некоторое время (поэтому ОЗУ так полезно).

Но если вы получаете что-то с удаленного сервера, у вас большие проблемы. Серверу может потребоваться 5 секунд или более, чтобы вернуть ответ, а в однопоточной программе это заблокирует основное выполнение, в результате чего ваша страница перестанет отвечать на запросы, а ваши пользователи уйдут.

Асинхронное программирование здесь, чтобы спасти пользователей. В JavaScript наиболее простой формой асинхронного кода является передача обратного вызова, обычно анонимной функции, которая запускается после завершения веб-запроса. Это можно сделать с помощью Ajax и других библиотек запросов.

ajax('https://example.com/api', (response) => {
   console.log(response);
});

Это может стать очень запутанным при работе с несколькими одновременными запросами и множеством функций, поэтому JavaScript создал промисы. Это объекты-оболочки, представляющие асинхронные переменные, которые все еще получают свои значения. Промисы могут быть возвращены при использовании таких функций, как встроенная в JavaScript функция fetch. Вы можете зарегистрировать функцию обратного вызова, используя .then(), что позволит вам объединить несколько запросов.

fetch('http://example.com/api')
  .then(response => response.json())
  .then(data => console.log(data));

Возврат такого объекта позволяет использовать другие функции, такие как Promise.All, которые могут выполнять несколько промисов и запускать один обратный вызов после их завершения.

Это огромный шаг вперед, но на самом деле это просто перемещение проблемы. Написание такого кода по-прежнему противоречит здравому смыслу, поскольку приходится управлять всеми запущенными промисами и следить за тем, чтобы все было в порядке. Если остальная часть вашего кода зависит от результата промиса, вам нужно переместить этот код в блок .then или вызвать отдельную функцию с данными.

В идеале было бы лучше просто не возиться с промисами и обратными вызовами. Вы хотели бы написать такой код, но JavaScript либо остановит выполнение программы, либо запустит ее не по порядку.

doSomething();
var response = fetch('http://example.com/api');
console.log(response.json());

Но есть лучший способ — async/await. Вам все равно придется работать с промисами в конце дня, но async/await предлагает лучший синтаксис для их использования.

Чтобы использовать его, вам нужно указать функцию как функцию async. Это гарантирует, что функция возвращает обещание, на которое JavaScript может воздействовать при вызове этой функции. Настоящая магия происходит с await, который вы можете добавить перед промисом, чтобы сообщить движку JavaScript, что эта функция займет немного времени, и она должна приостановить вашу асинхронную функцию до тех пор, пока она не вернется, освобождая время. выполнять другие действия и поддерживать работу приложения.

async function fetchAPI() {
    doSomething();
    var response = await fetch('http://example.com/api');
    console.log(response.json());
}

fetchAPI();

Теперь все в асинхронном блоке работает по порядку, но не останавливает выполнение программы для этого. Все, что идет после fetchAPI(), все равно будет выполняться не по порядку, так как fetchAPI() просто запускает выполнение асинхронной функции.

По сути, вы можете думать о await как о чем-то, что вы будете добавлять перед веб-запросами и другими вещами, которые требуют времени для возврата ответа. Его можно использовать только в асинхронной функции, и вы используете его для явного ожидания функции, которая возвращает обещание, а не для вызова .Then() и передачи обратного вызова.

Async/Await на других языках

Async/Await — это не просто концепция JavaScript; это функция многих других языков программирования, хотя точная реализация может немного отличаться.

Например, в C# есть задачи, которые функционируют как обещания и представляют собой асинхронную операцию, которая что-то возвращает. Вы можете ожидать других задач внутри асинхронной функции, что позволяет использовать неблокирующий код для таких операций, как выборка веб-запросов и запись/чтение с диска или внешних хранилищ данных, таких как корзины S3.

Вы можете связать их вместе, используя .ContinueWith(callback):

В зависимости от вашего приложения вам, возможно, придется неоднократно проверять в основном потоке, была ли задача выполнена. Например, у вас может быть сопрограмма, которая запускается один раз для каждого кадра и проверяет завершение задачи с помощью поля .IsCompleted . Если это не так, он уступает до следующего кадра, а если это так, он может продолжать обработку синхронно.