Kyle Edwards

Hacking Generators for Async/Await

const sleep = (delay) => ({ awaitable: 'setTimeout', args: [delay] });

function* createTask(name) {
  let i = 0;
  while (true) {
    console.log('awaiting', name, i)
    const result = yield sleep(1000 * Math.random());
    console.log('result', name, i, result);
    i++;
  }
}

const eventQueue = [];
let abort = false;

const asyncs = {
  'setTimeout': (args, cb) => {
    setTimeout(() => cb(args[0] || 1), args[0] || 1);
  }
}

let iter = 0;
function trampoline() {
  const task = eventQueue.shift();
  if (task) {
    const { value, done } = task.fn.next(task.result);
    const { awaitable, args } = value;
    if (!done) {
      if (asyncs[awaitable]) {
        asyncs[awaitable](args, (result) => {
          eventQueue.push({ fn: task.fn, result });
        })
      } else {
        eventQueue.push({ fn: task.fn, result: null });
      }
    }
  }
  iter++;
  if (!abort) setTimeout(trampoline, 0);
}

eventQueue.push({ fn: createTask('a'), args: [] });
eventQueue.push({ fn: createTask('b'), args: [] });
trampoline();