JS: Асинхронное программирование
Теория: Async/Await
Несмотря на все удобства, промисы не являются вершиной эволюции. Вспомним минусы, которые они добавляют:
- Своя собственная обработка ошибок, которая идёт в обход try/catch. Это значит, что в коде будут появляться оба способа обработки, комбинирующихся в причудливых формах
- Иногда бывает нужно передавать данные вниз по цепочке с самых верхних уровней, и с промисами делать это неудобно. Придётся создавать переменные вне промиса
- С промисами по-прежнему легко начать создавать вложенность, если специально за этим не следить
Все эти сложности убираются механизмом async/await, делающим код с промисами еще более похожим на синхронный! Вспомним нашу задачу по объединению двух файлов. Вот её код:
А теперь посмотрим на этот же код с использованием async/await. Подчеркну, что async/await работает с промисами:
Эта версия визуально практически не отличается от её синхронной версии. Код настолько простой, что даже не верится, что он асинхронный. Разберём его по порядку.
Первое, что мы видим, — это ключевое слово async перед определением функции. Оно означает, что данная функция всегда возвращает промис: const promise = unionFiles(...). Причём теперь не обязательно возвращать результат из этой функции явно, он всё равно станет промисом.
Внутри функции используется ключевое слово await, которое ставится перед вызовом функций, которые, в свою очередь, тоже возвращают промисы. Если результат этого вызова присваивается переменной или константе, то в них записывается результат вызова. Если присвоения нет, как в последнем вызове await, то происходит ожидание выполнения операции без использования её результата.
Асинхронность в данном случае (как и в промисах) гарантирует нам, что программа не блокируется в ожидании завершения вызовов, она может продолжать делать что-то еще (но не в этой функции). Но она не гарантирует параллельности. Более того, подряд идущие await в рамках одной функции всегда выполняются строго друг за другом. Проще всего это понимать, если представлять код как цепочку промисов, где каждая следующая операция выполняется внутри then.
А что с обработкой ошибок? Теперь достаточно поставить обычные try/catch и ошибки будут отловлены!
Однако, при параллельном выполнении промисов не обойтись без функции Promise.all:
Подводя итог, механизм async/await делает код максимально плоским и похожим на синхронный. Благодаря ему появляется возможность использовать try/catch, и легко манипулировать данными полученными в результате асинхронных операций.
Механизм async/await не отменяет промисы. Он лишь дает удобный интерфейс над промисами, являясь по сути синтаксическим сахаром. Внутри его основы лежат все те же промисы.





