Typescript: Transpiling async/await to promises instead of generators for es5

Created on 28 May 2019  路  2Comments  路  Source: microsoft/TypeScript

Search Terms

transpile async promise

Suggestion

When target is ES5, allow an option to transpile async/await to Promises rather than switches. This would require Promises to be polyfilled, hence would be optional.

Old issue for this

This was previously discussed on this issue but was closed with this comment by @mhegazy:

this may be true for code with small list of await expressions. but it does not scale for the general case. once you have a loop with an await expression, you can not use promises.

@mhegazy can you explain this? I have used fast-async to transpile loops to promises before. Is there some edge-case where it is not possible?

Use Cases

Current approach creates emitted code that cannot be source-mapped properly by some debuggers.

Examples

export const foo = async (): Promise<number> => await Promise.resolve(1) + 1;

Currently emits this:

exports.foo = function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
    switch (_a.label) {
        case 0: return [4 /*yield*/, Promise.resolve(1)];
        case 1: return [2 /*return*/, (_a.sent()) + 1];
    }
}); }); };

Instead it should emit something like this (output from fast-async:

exports.foo = function foo() {
  return new Promise(function ($return, $error) {
    return Promise.resolve(1).then(function ($await_7) {
      return $return($await_7 + 1);
    }.$asyncbind(this, $error), $error);
  });
};

Loops

Here's an example of fast-async transpiling a loop:

async function Foo() {
    for (let x = 0; x < 5; x++) {
        console.log("FOO: " + await Promise.resolve(x));
    }
}

becomes

function Foo() {
  return new Promise(function ($return, $error) {
    var x;
    x = 0;

    function $Loop_4_step() {
      x++;
      return $Loop_4;
    }

    function $Loop_4() {
      if (x < 5) {
        return Promise.resolve(x).then(function ($await_6) {
          console.log("FOO: " + $await_6);
          return $Loop_4_step;
        }.$asyncbind(this, $error), $error);
      } else return [1];
    }

    return Function.$asyncbind.trampoline(this, $Loop_4_exit, $Loop_4_step, $error, true)($Loop_4);

    function $Loop_4_exit() {
      return $return();
    }
  });
}

Here's a while loop:

async function Foo() {    
    let x = 0;
    while (x < 5) {
        x += await Promise.resolve(1);
        console.log("FOO: " + x);
    }
}

transpiles to:

function Foo() {
  return new Promise(function ($return, $error) {
    var x;
    x = 0;

    function $Loop_4() {
      if (x < 5) {
        return Promise.resolve(1).then(function ($await_6) {
          x += $await_6;
          console.log("FOO: " + x);
          return $Loop_4;
        }.$asyncbind(this, $error), $error);
      } else return [1];
    }

    return Function.$asyncbind.trampoline(this, $Loop_4_exit, $Loop_4, $error, true)($Loop_4);

    function $Loop_4_exit() {
      return $return();
    }
  });
}
Awaiting More Feedback Suggestion

Most helpful comment

+1 for this, would it be possible to integrate with fast-async?

All 2 comments

+1 for this, would it be possible to integrate with fast-async?

that's true, the current implementation is virtually impossible to understand/debug in production code that is shipped without source maps but with Promises simply pretty print of any debugger is enough.
Still, lots of enterprise products support IE11 and it makes usage of async/await impossible for such projects until the whole team learns how _awaiter works and code transpiled to Promises would be great if possible.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

manekinekko picture manekinekko  路  3Comments

kyasbal-1994 picture kyasbal-1994  路  3Comments

dlaberge picture dlaberge  路  3Comments

jbondc picture jbondc  路  3Comments

blendsdk picture blendsdk  路  3Comments