Skip to content

Latest commit

 

History

History
52 lines (44 loc) · 2.02 KB

emulate_async_await_with_generator.md

File metadata and controls

52 lines (44 loc) · 2.02 KB

Emulate async/await with generator

Using async/await:

const getData = async () => {
  const cfg = await readConfig();
  const authDetails = extractAuthDetails(cfg);
  const token = await fetchAuthToken(authDetails);
  const data = await secureFetch(DATA_URL, token);

  return data;
};

Before we had async/await, we could do something like this using generators:

const getData = asyncDo(function*() {
  const cfg = yield readConfig();
  const authDetails = extractAuthDetails(cfg);
  const token = yield fetchAuthToken(authDetails);
  const data = yield secureFetch(DATA_URL, token);

  return data;
});

const promiseForData = getData();

const asyncDo = (runTasks) => (...args) => {
  // We expect runTasks() to be a generator function,
  // like, for example, getData(). We first run it to
  // get a generator object.
  const generator = runTasks(...args);
  // Next, we create a recursive function that resolves
  // promises yielded by the generator function.
  const resolve = (next) => {
    // In any recursive function, we need to check to
    // see if we're done. Here we check the `done`
    // attribute returned from the generator result.
    if (next.done) return Promise.resolve(next.value);
    // We assume that `next.value` is always a promise.
    // If we haven't finished yet, then we grab the
    // value, and pass it back to the generator
    // using .next().
    return next.value.then(data => resolve(generator.next(data)));
  }

  // We kick the whole process off by calling resolve().
  return resolve(generator.next());
};

This is neat. But perhaps not so useful. Most of us won’t need to emulate async/await. But, that said, perhaps you use Babel (or similar) to make your code work with older browsers. If that’s the case, transpiler will use generators like this to make async/await work for you. And, because generators are so low-level, we can tinker with this yield pattern in ways we can’t with .next(). This allows authors to create interesting libraries that go beyond async/await.