Синтаксис async / await стал мощным дополнением к JavaScript, значительно улучшившим общий опыт разработчиков при работе с промисами.

Однако вы можете быть удивлены, узнав, что такой синтаксис не требует прямой языковой поддержки, но может быть реализован с использованием существующих функций JavaScript. Это забавная задача, которую мы постараемся решить в этой статье! «Как мы можем позволить разработчикам писать элегантный последовательный асинхронный код без всей этой беспорядочной цепочки?»

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

Вопрос, который мы должны рассмотреть, заключается в том, существует ли какая-либо другая функция JavaScript, позволяющая концептуально приостанавливать и продолжать выполнение функции? Фактически, функции-генераторы предлагают именно это! Итак, можем ли мы воспользоваться синтаксисом генератора для имитации чего-то, что ведет себя как синтаксис async/await? Ведь мы можем!

Поскольку мы можем использовать ключевое слово yield для приостановки выполнения функции, мы можем написать функцию-декоратор, которая перехватывает этот процесс и вместо этого моделирует поток асинхронного выполнения. Удивительно, но это заняло довольно много времени, но вот окончательное решение, которое на самом деле довольно простое:

Чтобы определить асинхронную функцию, мы определяем функцию-генератор и запускаем ее через указанный выше декоратор async. Мы приостанавливаем выполнение, давая обещание, которое затем ожидает наш декоратор. После разрешения или отклонения промиса вызываются методы next или throw протокола итератора для возобновления выполнения, и мы также передаем соответствующее значение или ошибку. Мы также позволяем предоставлять объекты, не основанные на обещаниях, чтобы упростить работу разработчиков. Когда функция генератора завершается, мы можем предположить, что последнее полученное значение является возвращаемым значением, и поэтому мы можем просто решить с этим значением. Кусок торта! - Я надеюсь.

Давайте посмотрим наше решение в действии!

Здесь мы определяем две асинхронные функции, spam и main, а внутри мы просто используем yieldдля ожидания любых промисов. Мы можем легко присвоить результат обещания переменной. Мы также можем продолжать использовать обычный поток обработки исключений JavaScript.

Вот вывод этой программы:

spam 0
spam 1
spam 2
spam 3
spam 4
we've enjoyed spamming you
error
5
end of showcase

Потрясающий!

Хорошей задачей для читателя будет настроить код для реализации функций асинхронного генератора. В этом случае нам понадобится функция, чтобы повторно ввести исходное поведение yield, сохраняя при этом нашу функциональность ожидания — каким-то образом.

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