06. In depth

Async Functions internally leverage both generators and promises:

async function example(a, b, c) {
  /* example function body */
}

// is compiled into...
function example(a, b, c) {
  return spawn(function*() {
    /* example function body */
  }, this);
}

In spawn, a promise is wrapped around code that will step through the generator function – made out of user code – in series, forwarding values to your “generator” code (the async function’s body).

In this sense, we can observe that Async Functions really are syntactic sugar on top of generators and promises, which makes it important that you understand how each of these things work in order to get a better understanding into how you can mix, match, and combine these different flavors of asynchronous code flows together.

function spawn(genF, self) {
  return new Promise((resolve, reject) => {
    const gen = genF.call(self);
    step(() => gen.next(undefined));

    function step(nextF) {
      let next;
      try {
        next = nextF();
      } catch (e) {
        // finished with failure, reject the promise
        reject(e);
        return;
      }
      if (next.done) {
        // finished with success, resolve the promise
        resolve(next.value);
        return;
      }
      // not finished, chain off the yielded promise and `step` again
      Promise.resolve(next.value).then(
        v => step(() => gen.next(v)),
        e => step(() => gen.throw(e))
      );
    }
  });
}

When the sequence is over or one of the promises is rejected, the promise returned by the underlying generator function is settled.

Можно комбинировать async/await вместе с Promise:

const delay = (time) =>
  new Promise((resolved, rejected) =>
    Math.random() > 0.5 ? setTimeout(() => resolved('done'), time) : rejected(new Error())
  );

async function Exec() {
  console.log('Sync');
  const res = await delay(2000)
    .then(() => 'then done')
    .catch(() => 'err');
  console.log(res);
  return res;
}

Exec();
console.log('super magic');

Last updated