Open MatAtBread opened 6 years ago
Have you guys looked at this plugin? https://github.com/rpetrich/babel-plugin-transform-async-to-promises
That plugin promises to turn async into promises but it does not fullfill it's promise. (😜)
It more turns it into a series of callbacks.
I prefer this one since it really does turn async calls into real promises (It can be a bit more restrictive in what it can translate though) https://www.npmjs.com/package/babel-plugin-async-to-promises
Indeed, a better name would have been transorm-async-to-callbacks-pyramid-hell
but that would not sell :D
I saw the one by Kneden but it as this big warning on top :fearful:
Indeed, a better name would have been
transorm-async-to-callbacks-pyramid-hell
but that would not sell :DI saw the one by Kneden but it as this big warning on top
I made comment on this a while ago and took a look at improving the implementation, but haven't had time.
TBH, I'm entirely baffled by the whole regenerator-runtime
choice in respect of await-async
- nearly all browsers have supported Promises
for years and those that don't can be polyfilled. Was regenerator-runtime
written before the Promises
spec came out?
I notice this PR has been inactive for a few months now - is there hope yet for this feature? We've been using fast-async
in the meantime (with transform-regenerator
and transform-async-to-generator
disabled), but it would be nice to know if this will have proper support in the near future.
Hi @dpraul - as far as I know, this is with the Babel guys to decide/approve
Hello @mAAdhaTTah and Babel Team (@nicolo-ribaudo, @hzoo)! Do you plan to continue work on this PR? What are the pending issues? Do you still see a value in this concept? If you need any help, I'm here for you!
I have no plans to a work on it.
It was left to @hzoo and the Babel team to decide whether to incorporate it or not
https://github.com/babel/babel/pull/7076#pullrequestreview-128418552 is a good summary of the minimum steps that need to be done to move this forward. However,
regenerator-runtime
when using async functions. If you configure @babel/preset-env
to target >0.6%, not ie 11
it will not use regenerator
, and if you lower your targets (>0.5%
or accept ie 11
) regenerator
is included for browsers that don't support promises anyway.transform-regenerator
and async-to-generator
in @babel/preset-env
's options.In the time that this PR has sat open the need for it has largely disappeared. Async function support is now up to above 90%. Still, thank you @MatAtBread for trying.
I don’t agree that the need has disappeared at all; I’d still very much like to see this land in core.
“90%” doesn’t mean anything; since everyone’s targets are different.
There is no need to remove the current approach when this one would be merged. It may be an option like a loose mode is for many presets, don't you think? In that way, everybody may choose what is best for a particular use case.
This transform really needs to be rewritten as a Babel plugin, as regenerator-transform has been for a long time (though not originally!), so that it can benefit from all the pipelining and NodePath/Scope-reuse optimizations that Babel's plugin system provides, and so that the Babel team can meaningfully maintain it, as you are implicitly asking them to do. Right now this plugin has a bus/vacation factor of 1, and that becomes a liability for Babel when it is included in core.
https://github.com/babel/babel/pull/7076#pullrequestreview-128418552
What would the use case be for preferring generators over promises though? 😕
@nicolo-ribaudo I meant an option to the preset, similar to modules
in env
(as far as I understand it's a case of adding a plugin conditionally).
@Dan503 I suppose compliance with specs would be the benefit of the original generator approach. Maybe there is something more, like handling more complex cases. I'm thinking about nested and conditional awaits, async generators etc.
In general, what I would like to accomplish is not having to advise people dropping async-await
syntax for simple cases, like unconditional series of asynchronous operations. I don't like multiple then
callbacks like everybody else, but what I don't like even more is that whole regenerator runtime and a lot of boilerplate added to the bundle just to handle the very simple cases. I also understand the necessity of having a fallback solution for more complex code, constructs that we may even not dream about. That's why I see a space for two separate and independent solutions, possibly chosen by a preset option.
I meant an option to the preset, similar to modules in env (as far as I understand it's a case of adding a plugin conditionally).
It doesn't matter if it's the default behavior or not. If it's not implemented as a Babel plugin we cannot maintain it. Nodent isn't a Babel plugin. It passes the original AST to an external compiler, which doesn't use Babel's architecture.
The whole compilation is opaque to us, and it's not something that we can maintain. The current implementation (as a "fake" plugin) can be published to npm, and then you can do:
{
"presets": [
["@babel/preset-env", {
"exclude": ["async-to-generator"]
}]
},
"plugins": [
"transform-async-with-nodent"
]
}
We have nothing against transpiling async to promises, but also the community is free to publish a plugin outside of preset-env.
I suppose compliance with specs would be the benefit of the original generator approach. Maybe there is something more, like handling more complex cases. I'm thinking about nested and conditional awaits, async generators etc.
@Dan503 This. :100:
Also, transpiling async functions to generators (not to es5) produces an output which is much more similar to the original one rather than when using promises:
// input
(async () => {
const response = await fetch(url);
const asJSON = await response.json();
console.log(asJSON);
})();
// Compiled to generators
_asyncToGenerator(function* () {
const response = yield fetch(url);
const asJSON = yield response.json();
console.log(asJSON);
})();
// Compiled to promises
(() => new Promise(function ($return, $error) {
let response, asJSON;
return fetch(url).then((function ($await_1) {
response = $await_1;
return response.json().then((function ($await_2) {
asJSON = $await_2;
console.log(asJSON);
return $return();
}).$asyncbind(this, $error), $error);
}).$asyncbind(this, $error), $error);
}))();
Additionally, I just noticed that nodent's output modifiers the native Function.prototype
object. It's not wrong per se, but it's something that so far we have been avoided on purpouse in Babel's generated code.
Actually, that's not true. It passes the parsed AST to nodent, which does all the tree transforms itself (not using the Babel utils).
I'm all in favour of debate, but please base it on facts. It did considerable work on factoring it the transformer especially for this PR. It's up to you if you use it, but don't misrepresent what it does
Thanks, I updated my comment.
In the short term, we could link the third-party plugin in Babel's docs.
Alright, I see the whole story now. If it's about maintainability and code ownership, maybe there is nothing wrong with rejecting this PR and continuing the work somewhere else? I suppose rewriting the code to Babel utils would require starting the work from scratch. It's far more than just polishing the code.
If we're focused on results more than on resolving technical or operational issues, maybe we should start from releasing a stable version of fast-async
working well with Babel@7, as a community plugin. Then we could try to measure its adaptation in the ecosystem and battle test in real-world projects. ~I'm not sure how wide is the usage of the plugin now, but NPM shows rather low numbers. Maybe refreshing the project and some marketing in social media would be enough to raise its popularity and get more feedback.~ The correct plugin is this one.
@nicolo-ribaudo, @MatAtBread, what do you think?
Whatever is appropriate for you.
As for maintainability, it is a complex piece of code, and quite old (the original implementation is maybe 5 years old). However, it has a full test suite in the main compiler (nodent, as opposed no nodent-transform which is just the AST transformer) which covers many more test cases than babel's current set and it has been in use in production systems for many years. I've not had to do anything to it for months to meet edge cases or indeed the spec (there are compiler flags for strict and loose adherence to the spec, along with options for output to ES5, Promises, ES6, etc).
If I remember correctly, the babel version defaults to strict adherence to the spec with no runtime at all and using Promises.
All that having been said, like last time this came up, this seems to be a "political" or "philosophical" debate. It's not about the code or it's functionality (which is fully in line with the rest of the world), it's about whether making the option available to end users of babel should be easy (included) or hard (a comment somewhere in the docs) vs. the potential cost of maintenance. This is not something I have a view on as I'm not a babel maintainer.
Matt, you're confusing me. Are you at work or having a sandwich break? 😐
Erm, both? It was lunch time in London.
I'm not trying to be confusing. I'm genuinely agnostic about whether Babel include the transformer or not. Most of my day job is backend, or if it's FE it's not for IE11, and I'm not a Babel user in general. So it really is whether there's a demand in the Babel user base for an async transformer with no runtime.
As an aside, when I first wrote it, it really was 10x quicker than regenerator & Promise polyfills, but now these are both implemented in major engines like V8, the point is moot as native is easily twice as quick as any userland implementations
Should you decide to integrate into Babel's core product, I'm happy to advise where I can, but it's not something I have an active interest in myself
I also think you're looking at the wrong plugin. Try https://www.npmjs.com/package/fast-async - that has 22k a week. I think someone built their own plugin on top of fast-sync for Babel & used the name
Just a stupid joke, you use two GitHub accounts interchangeably. I suppose by accident, but I found it funny because of the names. Sorry about that.
Do you refer runtime speed, right? I'm more interested in optimizing bundle size. I didn't consider potential improvement or regression in execution, but my gut feeling is Promises winning here as well, there is less code to run. On the other hand, there is some cost of creating many lambdas for then
callbacks... It's definitely something necessary to check out.
Huh, I'm looking at the wrong plugin! 😱
Oh yeah! I forgot. I have a paid-for-put-food-on-the-table and other stuff. It depends if I respond from my phone or desktop!
since this is showing activity again, just chiming in once more: if you're just trying to avoid using regenerator-runtime
for promises, we've been using fast-async
in production for a long time now with no issue.
@erykpiast - if you want the Babel-7 plugin, that I prepped for this PR, it's here: https://github.com/MatAtBread/fast-async/tree/babel-v7
@nicolo-ribaudo The comment about modifying the Function.prototype is a fair one, but you have not used the super-clean & spec options to test. Here's is the output with no runtime at all (function protoypical or otherwise).
Of course, it's even bigger and more ugly, but somewhat easier to read that regenerators output. Of course, if you have a runtime that does generators, you don't need either.
What's the latest story about this PR? Seems it has been open for a long time.
You can use the async-to-promises
plugin as shown in the config example at https://github.com/babel/babel/pull/7076#issuecomment-593412895
Have you guys looked at this plugin ? https://github.com/rpetrich/babel-plugin-transform-async-to-promises Just passing by :)