nodejs / node

Node.js JavaScript runtime ✨🐢🚀✨
https://nodejs.org
Other
104.76k stars 28.3k forks source link

Feature Request: Every async function returns Promise #11

Closed rdner closed 9 years ago

rdner commented 9 years ago

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.


jonathanong commented 9 years ago

https://github.com/iojs/io.js/issues/5 + time is a prerequisite IMO. otherwise, you can't do this without breaking people's shit.

rdner commented 9 years ago

What exactly will break "people's shit"? They still be able to work with callbacks, but also will have ability to do something like that:

server
  .listen(3000)
  .then(function() {
    // some action on ready event
   })

or they still can

server
  .listen(3000, function() {
    // some action on ready event
   })

Not only for servers of course, for every async function in node, including modules like fs, net, dns etc.

jonathanong commented 9 years ago

because some crypto functions without a callback actually return the result synchronously, so you can't change it to a promise without breaking API.

rdner commented 9 years ago

And they will do it without any changes. I said nothing about synchronous functions, only about asynchronous that work with callbacks now.

TJkrusinski commented 9 years ago

@pragmadash right, so since some of the crypto functions are variadic and operate synchronously in the absence of a callback they couldn't return a promise without breaking API changes.

darrenderidder commented 9 years ago

-1 Promises were explicitly removed from node years ago in favor of allowing flow control abstractions to be implemented in user modules. This has proven to be a good decision since it allows developers to work with abstractions they find appropriate while keeping core as simple as possible.

indutny commented 9 years ago

I'm not really a big user of user facing APIs, but when I do use them - I'd prefer callbacks over the promises. They don't have any overhead, and promises could be implemented on top of them. So -1 for promises.

Qard commented 9 years ago

There's also the issue that native promises in V8 are still kind of broken.

Speaking purely as someone that writes instrumentation for node, promises would be nice because I could just check if the return type of a call is a promise and tack on instrumentation via the then(...) function rather than manually searching the arguments for a callback which is error-prone.

In the long run, I think generators are a much better way to deal with asynchrony though. Even without any JIT optimization currently, they are substantially faster than promises. They aren't as fast as callbacks though. Callbacks work fine, and are currently the most efficient option.

vkurchatkin commented 9 years ago

There's also the issue that native promises in V8 are still kind of broken.

In what way?

medikoo commented 9 years ago

-1 While I'm fan of promises, I wouldn't like to see node.js API converted, @indutny put it well

Qard commented 9 years ago

@vkurchatkin

Unhandled rejection is still not a solved problem. Errors that occur in the context of a promise and are not explicitly handled in the usage of the promise do not propagate upward to anywhere that they can be handled: try/catch around the new Promise(...) doesn't catch them, domains don't catch them, etc.

https://gist.github.com/Qard/4758942da01a9b7dd6e1

vkurchatkin commented 9 years ago

@Qard it doesn't mean promises are broken. Everything works as defined by the spec

medikoo commented 9 years ago

@vkurchatkin exactly, they're broken by spec ;-)

Qard commented 9 years ago

@medikoo Agreed. Silent failure is very dangerous for production apps.

There was some recent attempt at adding a function to Isolate that could be given a callback to catch unhandled rejections. Not sure what the status of that is though. Until it's available in V8 and handled in node, I wouldn't consider native Promises a safe thing to use.

defunctzombie commented 9 years ago

This issue should be locked. It will be bikeshed to no end. ES as a language is still exploring the "async" space and how that will be handled. For now we should stick with core language features and less library features. Promises is a library feature. Functions are a language feature right now. In the future it may become clearer that what the idiomatic approach is.

jtmarmon commented 9 years ago

Imo this should just be revisited when ECMAScript 6 comes out with native promises

edit: wow, totally didn't know promises are native in v8. thanks for pointing that out @Qard

Qard commented 9 years ago

Native promises are already in V8. The issue is not native support, but a series of minor things like lack of error safety, and poor performance compared to callbacks. (Though bluebird has proven comparable native performance should be possible eventually)

rvagg commented 9 years ago

@Qard have you had a good look at the benchmark suite that bluebird uses to "prove" its claims? I'd take any results coming out of that with a grain of salt. I'm happy to admit they've made impressive progress with a heavy abstraction--but it's still a heavy abstraction that's more suitable for userland than core.

Qard commented 9 years ago

@rvagg Yep. I'm aware it's still a bit heavier than raw callbacks. It has improved substantially from initial implementations though, and from the state of the native implementation even, but callbacks are still better.

Perhaps someday promises will have comparable performance--particularly in combination with arrow functions, since they don't have the overhead of needing to create a new context. For now, callbacks are simply the best option and it's yet to be seen that any other will ever be better.

rlidwka commented 9 years ago

This issue should be locked. It will be bikeshed to no end. For now we should stick with core language features and less library features. Promises is a library feature.

I agree with that. It's easy enough to wrap node.js stuff in promises as is.

spion commented 9 years ago

I use and love promises, advocate them, am satisfied with the very low overhead of modern promise libraries and I think that Bluebird nails the error handling issue with its reporting of possibly unhandled errors.

That said, I still think that Promises don't belong in node core. I really like the libuv.js direction of exposing an even lower level API to userland and letting users decide on the high level abstractions that are best suited to their project.

The only thing I would like are more consistent lower-level APIs that are easier to e.g. automatically promisify on demand as well as richer Error types (more error codes and/or flags). Another thing that would really boost performance and lower memory use would be the ability to pass context objects to the api exposed by libuv.js which would give better optimization opportunities to all userland control flow libraries (not just promises)

YurySolovyov commented 9 years ago

-1. Core should be as lightweight as possible. Bluebird actually has a great feature called Promisification

ntkoso commented 9 years ago

Currently i'm using 'channels' instead of promises. Other users are using co with thunks. And even with promises there are multiple choices what library to use. Rewriting 'every async function' in core to 'new ES7\8\9+ standard way of handling async operations' every time the spec changes is bad idea.

KoryNunn commented 9 years ago

-1.

it is extremely trivial to convert CPS to Promises and there are libs to do this.

My hammer doesn't need Bluetooth.

MauriceButler commented 9 years ago

As @indutny said, I prefer callbacks over the promises. If you however prefer promises then that is fine, you can add your promise implementation of choice on top of that.

-1 for promises

SomeoneWeird commented 9 years ago

-1 not in core

hax commented 9 years ago

+1.

Promise is already in ES6 spec and most new W3C specs are based on Promise. Even Co has been refactored to promise based.

I believe there will be no other new async model in future ES7 -- note the aysnc/await proposol is also promise based.

darrenderidder commented 9 years ago

Promise whack-a-mole commence!

benjamingr commented 9 years ago

-1 promises are awesome, but converting the base class library to promises is already a:

var promisified = Promise.promisifyAll(require("yourModuleName")); 

Which works flawlessly with bluebird promises. That said - fixing stuff like fs.exists would be nice since it doesn't obey the convention.

Swaagie commented 9 years ago

I'll whack that mole then, -1 callbacks are as good as a convention/pattern as promises. That it is in the spec doesn't mean you have to use it. Op 4 dec. 2014 08:37 schreef "Benjamin Gruenbaum" <notifications@github.com

:

-1 promises are awesome, but converting the base class library to promises is already a:

var promisified = Promise.promisifyAll(require("yourModuleName"));

Which works flawlessly with bluebird promises. That said - fixing stuff like fs.exists would be nice since it doesn't obey the convention.

— Reply to this email directly or view it on GitHub https://github.com/iojs/io.js/issues/11#issuecomment-65547864.

hax commented 9 years ago

"callbacks are as good as a convention"

NO. callback is a BAD convention which force you to deal with error manually and make try...catch no use at all.

And please note that function (err, data) is only node.js convention, it's never been the conversion of browsers api.

benjamingr commented 9 years ago

@hax I don't like (err, data) any more than you do but making it into promises is pretty trivial today with libraries like bluebird..

hax commented 9 years ago

Yes it's trivial, so why not support promise natively without force developers introduce adapters themselves?

benjamingr commented 9 years ago

Because the adapters are trivial to make and the existing API is already there. This is solving something by the platform that can be easily solved by user-land code.

madbence commented 9 years ago

Native Promise is available in v8, ES7 async-await syntax will use promises. I prefer callbacks too, but the whole language moves towards the promise-based approach, so we should adopt to it too.

seidtgeist commented 9 years ago

I would like this, but it definitely needs a lot more ecosystem work first. It's going to be a series of things happening in order.

AFAIK we'll have a Promises constructor and generators from v8 in some post-1.0.0 version.

The ecosystem can then go ahead and experiment with those new primitives without having to rely on dependencies.

I think when all that happened we're in a much more informed situation than we are in now.

benjamingr commented 9 years ago

@ehd node 0.11.13 already ships native promises. They're worse than some libraries though.

darrenderidder commented 9 years ago

Promises are like Elvis. It's not the guy himself you hate, it's his fans you can't stand.

gx0r commented 9 years ago

+1 @spion

A few v8's ago, Bluebird was 40x faster than native promise. Native is faster now but still Bluebird is 6x faster than native. And native will never be faster than Bluebird.

jeffbski commented 9 years ago

-1 keep core standard with cb api, lean and efficient

drewhamlett commented 9 years ago

https://signalvnoise.com/posts/3124-give-it-five-minutes

cscott commented 9 years ago

+1 -- the Promise return value would be optional. If you pass a callback, you get exactly the same behavior as currently.

I'd propose that we avoid the APIs which currently behave differently depending on whether or not a callback is passed. Long term, I'd expect those APIs would want to be named consistent with the rest of node (ie, *Sync). But you don't have to push the boulder up the hill in one go.

(And nobody is forcing you to use Promises instead of callbacks; they are both available. And there is still the ability to build new abstractions on top of Promises or callbacks. ES7 will do this by building async on top of Promises, for example. It's just adding some sugar for folks who use Promises, because like it or not they are part of JavaScript now.)

gaearon commented 9 years ago

Agree with @spion. Bluebird nails error reporting with onPossiblyUnhandledRejection + onUnhandledRejectionHandled but this belongs to userland. For example, Bluebird provides faster promise perf than V8 promises, and it would suck if Node used V8 promises. Keeping them in userland allows faster further innovation.

cscott commented 9 years ago

@gaearon the ES6 expectation is that unhandled native promises will have native debugging support from the JS engine. Mozilla/firefox already implements this, and I believe the work is in-progress for Chrome/v8 as well.

drewhamlett commented 9 years ago

MINASWAN

nickpoorman commented 9 years ago

There's an elephant in the room which I think should be mentioned.

For a fork that's touting an open governance model, there seems to be an immediate striking down of promises (which I'm not in favor of), --with clearly slightly less than half it's community in favor of.

...just saying.

defunctzombie commented 9 years ago

Seems like exactly the reason to strike it down for now. As the language and project develops it might be more useful to revisit later. I think everyone involved is aware of the pros/cons and right now there is no consensus thus no change.

On Friday, December 5, 2014, Nicholas Poorman notifications@github.com wrote:

There's an elephant in the room which I think should be mentioned.

For a fork that's touting an open governance model, there seems to be an immediate striking down of promises (which I'm not in favor of), --with clearly slightly less than half it's community in favor of.

— Reply to this email directly or view it on GitHub https://github.com/iojs/io.js/issues/11#issuecomment-65845479.

ahdinosaur commented 9 years ago

:-1:

nmn commented 9 years ago

-1

The whole thinking behind this issue seems to be: "I like Promise, and I have to write like a few lines of code to promisify everything in Node Projects. That should just be a part of core"

Really? I love promises as much as the next guy. I use Bluebird in all my projects. (even with Koa/Generators).

Promises are powerful, and have been solved completely. There is not one benefit of putting promises into core, other than to save a you maybe a few lines of code.

You may say that callbacks are a bad pattern, but the fact is that callbacks are easy to understand, while Promises are a concept that is notorious for being difficult to explain. There is no point scaring beginners who come to node by showing them a bunch of code that uses Promises.

Plus, there are a whole bunch of code examples, where people are using Promises, JUST LIKE callbacks. a ).then( gets added, and many people don't even understand how Promise chaining works. That proves how difficult Promises are to understand for so many people.

cscott commented 9 years ago

No. The thinking is that Promise is being integrated into the JavaScript language, the runtimes, the debuggers, and all future web APIs, and in addition ES7 will introduce a new async function language construct based on Promises---so Node/io.js should integrate well with the modern language and web APIs.

If you read the proposal carefully, no one is forcing you to use promises instead of callbacks. You can still use all the existing callback-passing APIs. But new devs who come to the platform hoping to use modern JS language features and web APIs should not be forced to jump through hoops.

It's not about replacing callbacks, or even preferring Promises. The proposal is that Promise-using APIs should just be treated as equals.