Класс Promise появился в стандарте ES2015. Синтаксис async-await добавили в ES2017. Но на протяжении двух лет те, кто хотел писать «асинхронно в синхронном стиле» могли имитировать поведение async-await с помощью генераторов.
Наша задача — реализовать функцию runner
, с помощью которой можно будет писать асинхронный код, используя ключевое слово yield
вместо ключевого слова await
.
Допустим, мы хотим сложить два числа, а результат возвести в куб, и для этого у нас есть две асинхронные функции. Такой алгоритм можно реализовать, используя async/await
.
const sum = (a, b) => new Promise(r => setTimeout(r, 200, a + b)); const cube = num => new Promise(r => setTimeout(r, 300, num ** 3)); async function foo() { const res1 = await sum(1, 2); const res2 = await cube(res1); return res2; } foo(1, 2).then(console.log); // 27
Предположим, что у нас нет await
, а мы не хотим строить цепочки then
. Тогда функцию foo
можно реализовать как функцию-генератор. После ключевого слова yield
можно писать написать промис, разрешения которого мы будем дожидаться.
function* fooGen() { const res1 = yield sum(1, 2); const res2 = yield cube(res1); return res2; }
Естественно, если мы ее запустим, никакого результата мы не увидим.
Задача заключается в том, чтобы написать функцию runner
, которая принимает подобные функции-генераторы, запускает асинхронный код и возвращает промис с результатом функции-генератора.
runner(fooGen).then(console.log); // 27