Repository: TypeScript
Issue: Transpiling async/await to promises instead of generators for es5
Labels: Suggestion,Awaiting More Feedback

## 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](https://github.com/Microsoft/TypeScript/issues/11725) 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](https://github.com/MatAtBread/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();
    }
  });
}
```