Skip to content

Instantly share code, notes, and snippets.

@aravindet
Last active June 11, 2019 07:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aravindet/679251b8a547468811b5020a99e83559 to your computer and use it in GitHub Desktop.
Save aravindet/679251b8a547468811b5020a99e83559 to your computer and use it in GitHub Desktop.

Currently (March 2019) IE11 still needs to be supported, and this requires async/await to be transpiled. Babel's built-in path is to transform async-to-generator and use regenerator-runtime, which adds a significant bundle size penalty.

It would be preferable to transpile async/await to a Promise chain. There are several projects:

  • Kneden which is incomplete and seems abandoned
  • rpetrich's transform turns into a callback pyramid and not a promise chain
  • fast-async which focuses on runtime performance and not bundle size. It does not seem to have significant bundle size advantages over the regenerator approach.
    • A proposal to upstream this into babel proper seems stuck on disagreements over relying on an external non-babel library to do the transform.

This is a set of example transforms that produce compact code, and might form the basis for one more attempt at this.

async function foo() {
  const m = await bar();
  const n = await baz();
  return 3 + m / n;
}

function foo() {
  let m;
  let n;
  return Promise.resolve(bar())
  .then(_m => {
    m = _m;
    return baz();
  })
  .then(_n => {
    n = _m;
    return 3 + m / n
  });
}

// -----------------------

async function foo() {
  let x = 0;
  while (true) {
    const y = await bar();
    if (y === 0) return 50;
    if (y === 1) throw Error();
    if (y === 2) continue;
    if (y === 3) break;
    x += y;
  }
  return x;
}

const RETURN = Symbol();

function foo() {
  let x = 0;

  const _loop = () => {
    let y;
    return Promise.resolve(bar())
    .then(_y => {
      y = _y;
      if (y === 0) throw { [RETURN]: 50 };
      if (y === 1) throw Error();
      if (y === 2) return _loop();
      if (y === 3) return;
      x += y;
      return _loop();
    })
    .catch(_e => {
      // Return turner.
      if (typeof _e === 'object' && _e && _e[RETURN]) return _e[RETURN];
      throw _e;
    })
  }

  return _loop()
  .then(() => { return x; });
}

// -------------------------------

async function foo() {
  try {
    const x = await bar();
    if (x === 1) return x + 1;
  } catch (e) {
    await baz(e);
    if (e === 1) throw e;
    return 42;
  } finally {
    await bat();
  }
}


function foo() {
  let x;
  let e;

  return Promise.resolve(bar())
  .then(_x => {
    x = _x;
    // We throw the result so we can skip the catch's .then() chain
    if (x === 1) throw { [RETURN]: x + 1 };
    throw { [FINALLY] }; // This ensures finally is called
  })
  .catch(_e => {
    if (typeof _e === 'object' && _e && typeof _e[RETURN]) throw _e;
    e = _e;
    return baz(e);
  })
  .then(() => {
    // Continuing catch() block
    if (e === 1) throw e;
    throw { [RETURN]: 42 };
  })
  .then(() => { throw { [FINALLY] }; }) // This ensures finally is called
  .catch(() => {
    // Returned already? Pass through to the return-turning catch.
    if (typeof _e === 'object' && _e && typeof _e[RETURN]) throw _e;
    // This is "finally"
    return bat();
  })
  .then(() => {
  })
  .catch(_e => {
    // Return turner.
    if (typeof _e === 'object' && _e && _e[RETURN]) return _e[RETURN];
    throw _e;
  });
  
}

// ---------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment