async/await и генераторы в JavaScript 🕊️

Кажется, что async/await - это просто читаемый способ писать промисы. По спецификации под капотом совсем другое: движок реально приостанавливает и снова запускает контекст выполнения, поднимает и снимает его со стека. Не «синтаксический сахар», а тяжёлая механика.

Что по факту делает интерпретатор 👇🏻

❗️ async-функция - для тела создаётся отдельный контекст. На каждом await контекст снимается со стека и «засыпает», к промису вешаются коллбэки, а когда промис резолвится, контекст снова ставится на стек, и выполнение продолжается с результата. Буквально: приостановить контекст, потом снова возобновить.

❗️ Генератор - у объекта есть состояние, свой контекст и очередь запросов (каждый next/return/throw - запрос). Запуск = приостановить вызвавшего, поставить контекст генератора, выполнить до yield или выхода. Yield = завершить текущий запрос, отдать управление или взять следующий из очереди. Когда генератор завершился (return), движок ещё разбирает очередь накопившихся запросов и отдаёт им результат - это и есть «разбор очереди» при завершении. Всё то же: приостановка и возобновление контекста плюс очередь, а не «функция с паузой».

Поэтому для движка операция не такая простая: сохранение и восстановление контекста, стек вызовов, коллбэки промисов (всё это задано в 27.7.5 Await и 27.6.3 для генераторов). Удобнее писать async/await - код читается линейно. Но then-цепочка для интерпретатора легче: нет приостановки и возобновления контекста, только коллбэки. В горячих путях и бенчмарках это может давать разницу: then быстрее, async удобнее. Выбирать по задаче.

Итого: async/await и генераторы - сложные операции для движка (контекст, очередь, приостановка и возобновление). Удобство на стороне разработчика, нагрузка на стороне интерпретатора, а then проще для выполнения, хоть async приятнее писать. #js

async/await и генераторы в JavaScript 🕊️ | Сетка — социальная сеть от hh.ru