Closed rdner closed 9 years ago
For those annoyed by the promisifyAll calls, check out @tracker1 's https://github.com/tracker1/promisify-patch
Interesting approach of creating a Function.prototype.promise.
@cscott what would it do better than doing promisifyAll with Bluebird today?
-1, this should be on userland not core
Should Promises be implemented in io.js/Node core right now? NO, but we need to keep the discussion open and not immediately shut it down or close issues any time someone mentions Promises. That's my problem with the whole thing.
On the flip side, even though Bluebird takes a huge dump on native Promises, would it be that bad to have io.js support native promises right now, in core, for the people who would like to use them? They will get better, and personally even though I take a performance hit, I would never ever, ever, ever use callbacks again.
On the other flip side, it's not hard to do Bluebird.promisifyAll(require('fs'))
;
I agree with @cscott though. It's not that Promises are better or that they're even good at all, it's the fact that this is how the language is going to be moving forward. A lot of guys/girls in the front end community are providing Promise based API's as well as callbacks. jQuery, Angular, etc. As well as other places. For example the RethinkDB driver supports Promises as well as callbacks.
Good, I think we have established a consensus to keep promises outside of core for now but to keep the discussion open for later developments.
I would recommend keeping this issue open for all the Promisers to let off steam and argue, otherwise we'll just have new issues opened up in the future. Press the "Unsubscribe" button if it gets too noisy for you.
@rvagg for the record from what I can tell everyone here who has actually closely with promise libraries and watched/helped them evolve and usually advocates their use is against including them in core because the userland solution is good enough. So there is that.
<2-cents><steam>
Anyone talking about "Promise libraries" has the wrong idea here (whether you're arguing for or against). At most what should be discussed here is native Promises, and presumably for the intent of having compatibility with ES7 async
/ await
syntax.
It was previously stated that...
ES as a language is still exploring the "async" space and how that will be handled.
This is only partially true at this point. EcmaScript has standardized on Promises. It's a language feature that will eventually receive all the optimizations that other native features get, and I suspect that a few years from now callbacks will feel more and more like baggage from <=ES5 days. async
/ await
is obviously still somewhat speculative, but if you follow the es-discuss threads at all, it's at least 99% guaranteed at this point that whatever syntax sugar we get, it will rely on Promises.
I think the argument for them is extremely compelling at this point... but, meh. Apparently this thread is just for blowing off steam now, anyway. :)
</steam></2-cents>
@jmar777 I've created this issue exactly about native Promise, not to include any library into the core.
It is weird for me how people afraid of using new JavaScript language feature in node.js core. IMO Promise is the only way to deal with async workflow in right way. Yes, this is not simple for novices but it is common approach in other programming languages too, like Future in Scala and C++ and Task in C# for example.
I see the current discussion is made of the following concerns:
Bluebird.promisifyAll(require('fs'))
is ugly and non-standard. I have been thinking why not create these as npm modules that are managed by the io.js core community? These will be just like the standard libraries included in other programming languages. I understand that the core team might not want to be burdened by maintaining userland modules, and there is a risk of making standard libraries too bloated. But what I mean by standardization is to make it authoratative, carrying the io.js name, and be recommended on the io.js website.
We can discuss ways to manage the standard libraries, such as whether to include it preinstalled or require npm install; to create different committee to manage the standard libraries; to have review process of promoting individual npm modules to become standardized, etc.
In summary, we can get promise-based core API by making userland standard libraries that are standardized by the io.js community. If people are interested, I can open a new issue to have this discussion.
-1 for the time being, +1 for revisiting this request in six months or so.
@pragmadash Its not weird to me. A core issue of promises isn't solved by ES6: the missing .done(callback, errback)
method that provides a clear way of consuming a promise that isn't being used to construct another, which would result with proper reporting of errors. (Another solution is bluebird's possibly unhandled rejections, which I personally prefer, but changes promise semantics in an atypical way)
The path that ES6 promises have taken is expecting the browsers to solve this issue. The prevailing suggestion is that a list of currently rejected promises would be maintained by the browser and available when the debugger is opened. Each unhandled rejection would be removed from the list when handled. This clearly doesn't translate well to the server-side. As a result, barebones ES6 promises are just not suitable for use in node right now.
@soareschen
Promisifying callback-based API is trivial, but writing code like Bluebird.promisifyAll(require('fs')) is ugly and non-standard.
What's ugly about it? You just add one function call before calling require
and the entire API is now promise-enabled with faster-than-native promises who take care of error handling.
If there was no such alternative I'd be for native promises in code but since there is and this is a good solution in userland this should be
Have you tried using native promises in production yet? They suppress errors and bear a significant speed penalty when converting a callback API. This is because they don't have a strategy about error handling (in v8 afaik, FF uses GC to track them) and they require allocating a closure when promisifying. Even if we are to use promises eventually it would require engine hooks and support not currently available in order to have reasonable performance on servers. Userland solutions don't have neither of those problems.
Outside of being native (which, bluebird super-sets in terms of API). Native promises provide a worse solution in every aspect - they have worse error handling, require more memory, perform worse and require more work to be ready for prime time. I'm all for revisiting this in a few months but at the moment I see zero benefits for including native promises and a ton for not doing so.
@spion node-inspector will handle unresolved promises just as well for server side as it does for client side.
And again -- sure, some of the tooling isn't quite there yet. But (IMO) this bug is about seeing the writing on the wall and moving toward the future proactively, rather than waiting to be dragged kicking and screaming into the Promised land.
Also -- just to be clear -- I don't think @benjamingr is actually correct at all when he says "everyone here who has actually closely with promise libraries [...] is against including them in core because the userland solution is good enough." Both @domenic and I have been active in the standardization effort, and I maintain prfun
which is used by the Wikimedia Foundation's code.
Also, Promises are in core already -- open up node 0.11 and type Promise
at the prompt. So the question isn't about the userland -- I expect that people will continue to use bluebird
and prfun
and similar libraries to get a bit more sugar with their Promises -- but about using Promises cleanly with core APIs like the fs
module. And again, the Promise-returning variant would be optional.
@benjamingr's remarks make it clear his biases are showing. I could just as well say that callbacks suppress errors (who here has never seen someone ignore the err
parameter?) and bear a significant speed penalty (because I need to allocate a closure wrapper to promisify them in order to maintain sane error handling). The point is that it doesn't matter which style you prefer, you can support both, and you don't need to have any speed penalty for folks who prefer callbacks. The engine support will improve in time, ES6 has so decreed. (And, FWIW, Wikimedia is using Promises in production. As it turns out, any dispatch overhead from Promises is completely lost in the noise compared to the "real work" our servers are doing.)
@soareschen +1. But see also https://www.npmjs.org/search?q=promisify -- userland has spoken, and there are a bunch of modules doing roughly the same thing. It's about time to standardize one and embrace the future.
(All this said, I am curious about the governance model for iojs. Does @benjamingr just get to decide things arbitrarily? But that's a discussion more fit for a mailing list than a github issue.)
@cscott The "everyone who worked closely" referred to people commenting on this thread - now that you've showed up there is perhaps more room for debate.
Any effort would still require writing a mini-promise implementation and then call native Promise.resolve
on it in order to solve the extra-closure problem (that happens when promisifying with the promise constructor). Bluebird does a lot of work in order to promisify APIs quickly with little speed penalty. Any core implementation should not take a speed penalty (and certainly not make callback users take a speed penalty) for promisification.
Also - again like in my comment (2 above) to @soareschen I don't think v8 native promises are ready for prime time yet.
@cscott its not feasible to use node-inspector in production, yet its desirable that unhandled rejections get reported, preferably on stderr so that logging tools can gather the appropriate data. Because of that, I'm afraid that solution doesn't seem good enough to me.
slightly off-topic, I'm actually hoping that io.js provides the minimum neccessary low-level primitives to do IO, and the ability for any individual/company that is interested are able to provide a carefully crafted, high-level, ergonomic API on top of it (a distribution). In theory that leads to fragmentation, in practice I think people will quickly standardize on the most popular solution (e.g. caolan's async). Yes, ideally I'd vote for someone really good at architectural design and API design to do the entire standard library (e.g. Dart's library is amazing) but that would require some serious manpower and a larger company behind it. Besides, it can also be done on top of an io.js that only exposes low-level primitives.
What about just wrapping all of them in npm-space?
If you think promise based abstractions are valuable, build some modules that just do it, and if people find it helpful then they can use those instead of the core stuff.
@mikolalysenko - devil's advocate: it is very values or to have good defaults
@mikolalysenko npm-space works, although I'm slightly worried about peerDependencies being discoruaged as its the only way to sensibly do that in userspace (every single library dragging a copy of e.g. bluebird with it just doesn't work well and builtin promises are inadequate). Maybe we could make exported functions take an options object that lets you specify a Promise
object to use, defaulting to native promises.
Having an option to have something like "distributionDependencies", which behave more similarly to core modules (but are installed through npm) would be cool. Maybe peerDependencies are exactly that - except the package (e.g. bluebird) should be able indicate somehow that it prefers to be installed as a peerDependency if another package tries to pull it as a regular one (via a npm warning)
@spion Interesting. Does "npm dedupe" help in that case, or is that not ideal?
@llambda its not ideal because its rarely done, and besides it doesn't do anything for the typical use case (someone doing npm install --save bluebird
gets very strict restrictions in package.json by default). Maybe distributionDependencies
could default --save to a wide, major-version range?
In any case, the promise issue is better solved outside core, perhaps with better support from npm for "core-like" packages :)
Probably worth mentioning that if io.js did decide to embrace Promises, it's reasonable to think that would include some sort of unhandled rejection tracking, so I'm not too concerned about that particular aspect.
@pragmadash Oops, missed your reply earlier. Just to be clear, my thoughts were in reference to comments like:
Promises is a library feature. Functions are a language feature right now.
I understand you weren't suggesting dragging Q, Bluebird, etc. into core. :)
I understand you weren't suggesting dragging Q, Bluebird, etc. into core. :)
If we take into consideration that fact that native promises suck, dragging Bluebird into core isn't seem like such a bad idea...
I wonder, why es6 promises don't have unhandled rejection tracking like many other libs do?
Another small note on this: I think io.js adoption would soar through the roof if or when Promises get in core. That would be a feature worth writing home about. Not Streams version 9000, documentation, or faster V8 version upgrades.
@rlidwka
I wonder, why es6 promises don't have unhandled rejection tracking like many other libs do?
This has been the source of a lot of discussion on es-discuss. There's probably more to it than this, but here's the gist of it:
Whereas some libraries, like Bluebird, expect rejection handlers to be registered during the same turn on the event loop (making unhandled rejections straight forward to identify), ES6 Promises are designed to allow rejection handlers to be added at any stage during the Promise's life cycle. E.g.,
var p = Promise.reject('just because');
setTimeout(function() {
p.catch(rejectionHandler);
}, 99999);
While the above will work fine with ES6 Promises, my understanding is that Bluebird would have reported p
as being unhandled almost immediately.
Anyway, that's probably the most fundamental API difference between ES6 Promises and most of the non-standard libraries. One of the downsides of this API decision is that it becomes very hard to decide when a rejection is really and truly unhandled in a deterministic way (i.e., the "when" becomes implementation specific, and for now tends to rely on non-deterministic events, like when the promise is about to be garbage collected). For those reasons, TC39 has currently just suggested that engines/browsers surface unhandled rejections in a way that developers will know about them (e.g., log it somewhere).
So, long story short, ES6 Promises don't have unhandled rejection tracking because TC39 opted to punt that responsibility to implementors, and the combination of V8/node(/io.js) doesn't follow that suggestion yet.
P.S. There have been suggestions for something like promise.onUnhandledRejection(handler)
which haven't been outright dismissed, but have at a minimum been barred from consideration prior to ES7.
@jmar777
While the above will work fine with ES6 Promises, my understanding is that Bluebird would have reported p as being unhandled almost immediately.
This is somewhat incorrect. There's a reason Bluebird offers two hooks for handling rejections:
The first fires as you described, the second fires if previously reported “possibly unhandled” rejection got handled after all.
The thinking beside this is that it's up the user to decide what to do with possibly unhandled rejections.
For example, in a debugger, one might show a stack of all currently possible unhandled rejections, and remove them from the stack once they're handled:
var unhandledPromises = [];
Promise.onPossiblyUnhandledRejection(function(reason, promise) {
unhandledPromises.push(promise);
//Update some debugger UI
});
Promise.onUnhandledRejectionHandled(function(promise) {
var index = unhandledPromises.indexOf(promise);
unhandledPromises.splice(index, 1);
//Update the debugger UI
});
In a server environment, one may decide to report unhandled rejections to a user-supplied handler after they've been in “possibly unhandled” list for some period of time.
IMO it's the most sane solution to the problem, taking async-first nature of promises into account and not trying to shy away from it.
Since this thread is totally derailed into unhandled rejection territory anyway I'll just leave this here:
http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Sep/0024.html
@domenic Does this match what Bluebird is doing, or do I miss some detail?
@gaearon given that adding onUnhandledRejectionHandled
in Bluebird was @domenic 's idea that makes sense :P
Ah, never realized this. :+1: It's awesome.
@cscott also I did not decide anything - I summed up the opinions raised in this thread and argued the stance I believe is correct. I'm certainly not against promises and I'm not sure why you'd think I'm biased against them. I've been active in the "promise community" and have the most answers (over 300) and most points for promises in Stack Overflow, I certainly am for having promises. I'm not anti-promise, I use promises in my personal projects and have integrated them in all of TipRanks' JS projects both in client and node.
My entire argument here just like @spion's is that while people may or may not like promises and prefer them to callbacks (or not) - because of the state of native promises and how they keep evolving and solving their issues we should not include them in core at the moment. Userland solutions are good enough in order to delay this discussion a few more months until v8 has unhandled rejection rejection and a fast way to promisify - once those issues are out of the way (and they will be) I am all for reconsidering this issue.
Also - the error suppression argument is about synchronous throws.
@rvagg It's alright to re-open this as a place for Promise fans to "let off steam", but somehow TC needs to better educate the community about why Promises aren't the right abstraction for the core APIs.
Here's some perspective that might be useful to the Promise folks:
First, callbacks are not as bad as you think and there are some simple, effective ways to organize callback driven code to avoid common complaints: http://andrewkelley.me/post/js-callback-organization.html
Second, Promises have costs and benefits like anything, and while the benefits are well-advertised, the costs can be hidden and frustrating: http://sealedabstract.com/code/broken-promises/
Third, the callback is the fundamental unit of asynchronous programming in JavaScript, and Promises are only one of several high-level abstractions built on top of them. There is no single abstraction that's perfect for all use cases: http://r.va.gg/presentations/webdirections-code-2014/#20
Fourth, Promises aren't a silver bulllet. There are whole classes of use cases where Promises aren't the right abstraction: incremental processing, event handling, temporal logic, etc. Streams, event emitters and functional reactive programming can be more effective abstractions for event-driven systems. http://eamodeorubio.github.io/tamingasync/#/23
Fifth, the design philosophy of node core is to encourage maximum compatibility and discourage decisions that lead to incompatibility. This has led to a decision that flow control is not defined in the core APIs. Anybody who is wondering about Promises and Node really needs to read this: http://www.futurealoof.com/posts/broken-promises.html
Sixth, integrating with c++ bindings/libuv has only been possible using callbacks. The core team is committed to keeping node lightweight and fast by providing APIs that are as "close to the action" as possible, so they're not going to be introducing a new abstraction to asynchronous programming in core anytime soon: http://blog.trevnorris.com/2014/02/nodejs-es6-and-me.html
You have some good options already for using Promises if that's the paradigm that makes sense to you. For a bunch of other developers and their use-cases, it doesn't make sense. The diversity of the node community is best addressed by leaving high-level abstractions out of core and continuing to implement them in user modules.
I have to agree with the points @darrenderidder makes... I don't think the core API should use promises... there is a lot of overhead to them, let alone compatibility issues.
I wrote promisify-patch to make it pretty easy to promisify callback calls... the only small gotcha, is if the method needs to be bound to its' context... (you should also bring in es6-promise if you don't have a compatible implementation, which shouldn't be an issue for iojs 1.x)
require('promisify-patch').patch(); //adds promise method on Function.prototype;
...
fs.readDir.promise('./').then(function(files){
...
});
...
foo.bar.bind(foo).promise(arg1).then(function(result){
...
});
I like the approach better than the promisifyAll
type methods... also, it would be reasonable to continue to create abstracted interfaces on top of the underlying compatible interfaces... fs-promise
vs fs
... etc.
@tracker1 only tangentially related to this post but your implementation is going to be unacceptably slow for many use cases, it uses a load of constructs that V8 cannot optimise and relies on some slow builtins (e.g. Function::bind()
)
@phpnode in those cases, promises themselves are probably unacceptably slow, and you should be using the callback methods. I was mainly offering an alternative to promisify-ing the world in iojs.
@tracker1 bluebird proves that promises can be almost as fast as callbacks, the idea that promises have to be "slow" is damaging imho.
@tracker1
in those cases, promises themselves are probably unacceptably slow
But they're not. This is simply not true. It is possible to optimize promises to work almost as well as callbacks (which is what Bluebird did). Yes, it's tricky, but it's definitely possible, and saying they're slow is subverting the effort people put into this. Promises have left only-if-you-don't-care-about-perf-land quite some time ago, and encouraging bad perf patterns “just because promises are slow anyway” is hurting their adoption. Check out Optimization Killers by Bluebird author.
@phpnode they can even be faster
@tracker1 that's not true, for example bluebird promises are definitely fast enough in those cases. Run a benchmark and see for yourself or compare promisify.js
in Bluebird to what you do.
@darrenderidder generally I agree with the end line but I don't really appreciate the FUD. To address your issues:
First, callbacks are not as bad as you think and there are some simple, effective ways to organize callback driven code to avoid common complaints.
Promises are an abstraction pioneered by CS research finest to solve the temporal value issue. They are used idiomatically by most other languages who perform this task like Scala, C++, Dart, C#, Python, Haskell, F# and so on. Promises offer advantages like easy aggregation, implicit "no error swallowed" error handling and a solid abstraction over a value not being available yet.
People who want promises are not complaining about syntax, they are complaining about semantics.
Second, Promises have costs and benefits like anything, and while the benefits are well-advertised, the costs can be hidden and frustrating:
Addressing the problems in the article quickly one by one:
Promise.using
in bluebird - it's a hard problem (same with callbacks) but you generally use the disposer pattern to address it. In general the article amounts to "promises are not good everything async" which is obviously correct, we are only discussing them in the (err, data)
use case. No one is suggesting promises for every concurrency issue - for a good read on that read @kriskowal 's https://github.com/kriskowal/gtor
Third, the callback is the fundamental unit of asynchronous programming in JavaScript, and Promises are only one of several high-level abstractions built on top of them. There is no single abstraction that's perfect for all use cases:
Not in ES6. In ES6 promises are a low-level language concept built into the language and is a part of it. Just as much as callbacks.
Fourth, Promises aren't a silver bulllet. There are whole classes of use cases where Promises aren't the right abstraction: incremental processing, event handling, temporal logic, etc. Streams, event emitters and functional reactive programming can be more effective abstractions for event-driven systems.
Duh... again, not one is calling to replace event emitters or streams or observables in general with promises. Only nodebacks with (err, data)
signature and when appropriate. You might want to watch this lecture.
Fifth, the design philosophy of node core is to encourage maximum compatibility and discourage decisions that lead to incompatibility.
I don't disagree with that, at least until promises are stable in core and people start using them as the go-to mechanism for called-once, asynchronous callbacks that might error.
Sixth, integrating with c++ bindings/libuv has only been possible using callbacks.
That probably won't be a big issue. As for the post read @spion 's comment there (Gorgi Kosev) I agree with that.
putting this on the TC agenda for this week, will hopefully come back with a stance from TC to post here to provide some more clarity
So I went away and wrote some code to make things a bit more concrete. Voila: https://www.npmjs.org/package/pn
This is functional and works. I'm not saying its blazing fast or that node should use this particular implementation in core. The point of pn
is to show what node's native APIs could look like, embracing both Promise and callback users.
For the purposes of this discussion, the relevant stuff is at https://github.com/cscott/node-pn#exceptions-and-odd-cases which lists those node APIs which are awkward to migrate.
It's also notable that pn
has trouble promisifying object methods which are created by factory methods in node. Stream, Server, etc. This is precisely the part of the problem which userland approaches cannot currently do well --- you either need to write to global prototypes or use Proxy objects. So there's a benefit to doing this in core. (Although patches welcome if you can figure out how to do more wrapping in userland and/or make the wrappers faster.)
I've been using the ES6 promise on a few projects, and I really think that they're awesome and should be used by iojs (and nodejs on a longer timespan). The main advantage was their ability to work with the ES7 async proposal, which basically remove all the syntaxic burden from the source code:
async function getJsonFile(path) {
if (!(await state(path)).isFile())
throw new Error('Expecting a file');
var content = await readFile(path);
return JSON.parse(content);
}
Working on an application with such a syntax, even if it currently requires to use Traceur, is really, truly great. The code ends up quite clean, whilst still avoiding to block.
This pattern is also possible with the ES6 generators, with a few gotcha.
@Qard Chrome is now already displaying uncatched promises, and I guess it will be improved.
node reflections... Suggesting that promises should go back into core
-1, it just one of the patterns to resolve the callback hell
issue. And there're many other way to achieve the same goal.
There is another choice for someone who like CPS function: https://github.com/thunks/thunks
Thinking and programming in thunks is similar to that in native Promise, and it is functional. It support generator (like co), and support generator in chain!
'use strict';
/*global module, process*/
var Thunk = require('../thunks.js')();
var fs = require('fs');
var size = Thunk.thunkify(fs.stat);
size('.gitignore')(function (error, res) {
console.log(error, res);
return size('thunks.js');
})(function (error, res) {
console.log(error, res);
return size('package.json');
})(function* (error, res) {
console.log(error, res);
// generator
var a = yield size('.gitignore');
var b = yield size('thunks.js');
var c = yield size('package.json');
console.log(a);
console.log(b);
console.log(c);
})();
Debug and error catch in a scope:
var thunks = require('thunks');
var Thunk = thunks({
onerror: function (error) {
console.error(error);
},
debug: function () {
console.log.apply(console, arguments);
}
});
Thunk(function* () {
// do some thing ...
});
co
:+1:
FWIW the bugs tracking this on V8 and Chromium are https://code.google.com/p/chromium/issues/detail?id=393913 https://code.google.com/p/v8/issues/detail?id=3093
This talk just came out discussing ES6 and ES7 generators/yield, async/await, and promises/observables at a high level and long term plan: https://www.youtube.com/watch?v=DqMFX91ToLw
Take aways: promises hopefully will be better optimized by runtimes, though will still a performance cost. Use promises when you want composition, callbacks when you want performance.
Use observables when you want composition, node streams for performance. Similar to iterators vs. arrays.
This was discussed at the TC meeting today, see #144, the aim was to be able to provide at least some kind of statement as feedback in this issue. I don't think the issue needs to be closed and can continue to collect discussion from those who feel strongly about this topic.
The feedback from the TC about incorporating a Promises-based API in core goes something like this:
A Promises API doesn’t make sense for core right now because it's too early in the evolution of V8-based promises and their relationship to other ES* features. There is very little interest within the TC in exploring this in core in the short-term.
However, the TC is open to change as the feature specifications and implementations in ES6 and ES7 are worked out. The TC is open to experimentation and providing the most optimal API for users, which may potentially include a Promises-based API, particularly if newer features of JavaScript work most optimally in conjunction with Promises. The speed of the language specification process and V8 implementation will mostly dictate the timeline.
It should be noted that a callback API is unlikely to ever go away.
(Note: I'm ad libbing here a little from the written notes from the meeting, you should watch the video recording of the meeting to get the full vibe of it, I'll ping TC members to make sure they're happy with my representation of the conversation.)
Now in node we have callback or EventEmitter model to deal with async calls by default. But in my opinion it is better if every async function returns a native Promise (from new version of V8). It does not break backward compatibility and supports optional callback if needed.
If so we just do not need to install additional package for promises like q or bluebird except additional functionality is needed.
_EDIT 2014-12-11 by @rvagg_
Comment lifted from here so it's easier to see for newcomers to this conversation.
This was discussed at the TC meeting yesterday, see #144, the aim was to be able to provide at least some kind of statement as feedback in this issue. I don't think the issue needs to be closed and can continue to collect discussion from those who feel strongly about this topic.
The feedback from the TC about incorporating a Promises-based API in core goes something like this:
A Promises API doesn’t make sense for core right now because it's too early in the evolution of V8-based promises and their relationship to other ES* features. There is very little interest within the TC in exploring this in core in the short-term.
However, the TC is open to change as the feature specifications and implementations in ES6 and ES7 are worked out. The TC is open to experimentation and providing the most optimal API for users, which may potentially include a Promises-based API, particularly if newer features of JavaScript work most optimally in conjunction with Promises. The speed of the language specification process and V8 implementation will mostly dictate the timeline.
It should be noted that a callback API is unlikely to ever go away.