microsoft / microsoft/TypeScript

Transpiling async/await to promises instead of generators for es5

Open
#31,621 2 comments 9 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Awaiting More Feedback Suggestion
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
2d 4h
Merged PRs (30d)
132

Description

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();
    }
  });
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the ES5 async/await transpilation path and the prior discussion in issue 11725. Compare the requested Promise-based output with the single-await and loop examples, including source-map behavior. Done means an optional Promise-based target is defined for these cases and its behavior and limitations are covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.