microsoft / microsoft/TypeScript
Transpiling async/await to promises instead of generators for es5
Nobody has claimed this yet.
- 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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