Асинхронное программирование на JavaScript: делаем код удобнее и быстрее

0

Асинхронное программирование сравнительно молодой инструмент, но уже стал популярным в Javascript, C# и Python. Если ранее разработчикам приходилось обращаясь к серверу ждать ответа, чтобы выполнить следующее действие, то сегодня выполнять процессы можно параллельно. Рано или поздно даже junior программистам придется научиться асинхронным возможностям.

От ада в коде до понятных слов

Еще недавно разработчики использовали «колбэки» (callback-скрипт). Код становился монструозным, неудобным и тяжело читаемым. Не случайно результат часто называют «колбэк хелл». Затем в помощь разработчикам пришли «промисы» (promises) — объекты, содержащие состояния ожидания (pending), успешного и неуспешного выполнения (fulfilled и rejected). На них «навешиваются» «колбэки» onFulfilled или onRejected. Использование «промисов» все еще популярно среди программистов любого уровня за счет гибкости.

Однако метод уступает по удобству простым и понятным ключевым словам async и await. Первое — оборачивает возвращаемое значение в «промис», а второе останавливает выполнение для получения результата, но не блокирует остальной код. Использование ключевых слов заметно ускоряет процесс написания и выполнения процессов.

Я бы предостерег начинающих программистов от async и await прямо сейчас. Для начала необходимо изучить базу языка, понять «колбэки» и «промисы». Никто не заставляет вас использовать старые методы, но для общего понимания — это необходимо.

Было-стало

Рассмотрим пример синхронного кода, который делает следующее:

1) запрашивает json со стороннего ресурса, с использованием XMLHttpRequest 2 раза

2) выводит в консоль 10 раз число 1000000;

3) опять запрашивает json со стороннего ресурса, но уже один раз;

4) опять выводит в консоль 10 раз число 1000000;

5) и еще раз запрашивает json со стороннего ресурса;

let url = «https://jsonplaceholder.typicode.com/comments»;//url для запроса данных

let request = new XMLHttpRequest();//объект для обращения к ресурсу

function get(url, n) {//синхронная функция, в которой отправляется запрос на url с индексом n для опознавания функции получаются данные

console.log(«waiting to fetch…», n);//вывод сообщения

request.open(«GET», url, false)//формирование

request.send(null);//и отправление запроса(блокирующая операция)

console.log(«after fetching…», n);//вывод сообщения

console.log(«waiting to get json…», n);//вывод сообщения

const json =  JSON.parse(request.responseText);//парсинг данных(блокирующая операция)

console.log(«after getting json…», n);//вывод сообщения

console.log(json);//вывод json данных

}

get(url, 1);//синхронный вызов функции

get(url, 2);//синхронный вызов функции

for (let index = 0; index < 10; index++) {//дополнительные действия

console.log(1000000);//вывод сообщения

}

get(url, 3);//синхронный вызов функции

for (let index = 0; index < 10; index++) {//дополнительные действия

console.log(1000000);//вывод сообщения

}

get(url, 4);//синхронный вызов функции

Теперь рассмотрим аналогичный пример, но уже с асинхронным программированием и использованием функций async и await.

let url = «https://jsonplaceholder.typicode.com/comments»;

async function async_get(url, n) {//асинхронная функция, в которой отправляется запрос на url с индексом n для опознавания функции получаются данные

console.log(«waiting to fetch…», n);//вывод сообщения

const response = await fetch(url);//асинхронный запрос

console.log(«after fetching…», n);//вывод сообщения

console.log(«waiting to get json…», n);//вывод сообщения

const json = await response.json();//асинхронный парсинг

console.log(«after getting json…», n);//вывод сообщения

console.log(json);//вывод json сообщения

}

Делают вызов fetch и response.json неблокирующими основной процесс. Таким образом, в момент await управление передается в другую функцию, которая будет выполняться до тех пор, пока не встретит await уже она.

async_get(url, 1);//асинхронный вызов функции

async_get(url, 2);//асинхронный вызов функции

for (let index = 0; index < 10; index++) {//дополнительные действия

console.log(1000000);//вывод сообщения

}

async_get(url, 3);//асинхронный вызов функции

for (let index = 0; index < 10; index++) {//дополнительные действия

console.log(1000000);//вывод сообщения

}

async_get(url, 4);//асинхронный вызов функции

Вызов функции async_get не блокирует остальную программу. При выполнении второй программы, можно заметить как в консоли будут появляться сообщения из async_get со вторым аргументом 1, 2, 3 и 4 одновременно — программа не будет дожидаться пока закончится выполнение asyc_get(url, 1) перед тем, как выполнить async_get(url, 2), и так далее.

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

Михаил Ефимов
Share.

About Author

Full stack разработчик, преподаватель Luxoft Training, автор методических материалов.

Comments are closed.