Coder Social home page Coder Social logo

Comments (323)

jonathanong avatar jonathanong commented on April 28, 2024

#5 + time is a prerequisite IMO. otherwise, you can't do this without breaking people's shit.

from node.

rdner avatar rdner commented on April 28, 2024

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.

from node.

jonathanong avatar jonathanong commented on April 28, 2024

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

from node.

rdner avatar rdner commented on April 28, 2024

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

from node.

TJkrusinski avatar TJkrusinski commented on April 28, 2024

@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.

from node.

darrenderidder avatar darrenderidder commented on April 28, 2024

-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.

from node.

indutny avatar indutny commented on April 28, 2024

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.

from node.

Qard avatar Qard commented on April 28, 2024

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.

from node.

vkurchatkin avatar vkurchatkin commented on April 28, 2024

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

In what way?

from node.

medikoo avatar medikoo commented on April 28, 2024

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

from node.

Qard avatar Qard commented on April 28, 2024

@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

from node.

vkurchatkin avatar vkurchatkin commented on April 28, 2024

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

from node.

medikoo avatar medikoo commented on April 28, 2024

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

from node.

Qard avatar Qard commented on April 28, 2024

@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.

from node.

defunctzombie avatar defunctzombie commented on April 28, 2024

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.

from node.

jtmarmon avatar jtmarmon commented on April 28, 2024

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

from node.

Qard avatar Qard commented on April 28, 2024

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)

from node.

rvagg avatar rvagg commented on April 28, 2024

@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.

from node.

Qard avatar Qard commented on April 28, 2024

@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.

from node.

rlidwka avatar rlidwka commented on April 28, 2024

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.

from node.

spion avatar spion commented on April 28, 2024

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)

from node.

YurySolovyov avatar YurySolovyov commented on April 28, 2024

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

from node.

ntkoso avatar ntkoso commented on April 28, 2024

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.

from node.

KoryNunn avatar KoryNunn commented on April 28, 2024

-1.

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

My hammer doesn't need Bluetooth.

from node.

MauriceButler avatar MauriceButler commented on April 28, 2024

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

from node.

SomeoneWeird avatar SomeoneWeird commented on April 28, 2024

-1 not in core

from node.

hax avatar hax commented on April 28, 2024

+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.

from node.

darrenderidder avatar darrenderidder commented on April 28, 2024

Promise whack-a-mole commence!

from node.

benjamingr avatar benjamingr commented on April 28, 2024

-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.

from node.

Swaagie avatar Swaagie commented on April 28, 2024

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" <[email protected]

:

-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
#11 (comment).

from node.

hax avatar hax commented on April 28, 2024

"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.

from node.

benjamingr avatar benjamingr commented on April 28, 2024

@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..

from node.

hax avatar hax commented on April 28, 2024

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

from node.

benjamingr avatar benjamingr commented on April 28, 2024

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.

from node.

madbence avatar madbence commented on April 28, 2024

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.

from node.

seidtgeist avatar seidtgeist commented on April 28, 2024

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.

from node.

benjamingr avatar benjamingr commented on April 28, 2024

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

from node.

darrenderidder avatar darrenderidder commented on April 28, 2024

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

from node.

gx0r avatar gx0r commented on April 28, 2024

+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.

from node.

jeffbski avatar jeffbski commented on April 28, 2024

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

from node.

drewhamlett avatar drewhamlett commented on April 28, 2024

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

from node.

cscott avatar cscott commented on April 28, 2024

+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.)

from node.

gaearon avatar gaearon commented on April 28, 2024

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.

from node.

cscott avatar cscott commented on April 28, 2024

@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.

from node.

drewhamlett avatar drewhamlett commented on April 28, 2024

MINASWAN

from node.

nickpoorman avatar nickpoorman commented on April 28, 2024

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.

from node.

defunctzombie avatar defunctzombie commented on April 28, 2024

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 [email protected]
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
#11 (comment).

from node.

ahdinosaur avatar ahdinosaur commented on April 28, 2024

👎

from node.

nmn avatar nmn commented on April 28, 2024

-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.

from node.

cscott avatar cscott commented on April 28, 2024

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.

from node.

gx0r avatar gx0r commented on April 28, 2024

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.

from node.

benjamingr avatar benjamingr commented on April 28, 2024

@cscott what would it do better than doing promisifyAll with Bluebird today?

from node.

julianduque avatar julianduque commented on April 28, 2024

-1, this should be on userland not core

from node.

drewhamlett avatar drewhamlett commented on April 28, 2024

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.

from node.

benjamingr avatar benjamingr commented on April 28, 2024

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.

from node.

rvagg avatar rvagg commented on April 28, 2024

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.

from node.

benjamingr avatar benjamingr commented on April 28, 2024

@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.

from node.

jmar777 avatar jmar777 commented on April 28, 2024

<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>

from node.

rdner avatar rdner commented on April 28, 2024

@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.

from node.

soareschen avatar soareschen commented on April 28, 2024

I see the current discussion is made of the following concerns:

  • The core team want to keep io.js core minimal. Anything that is trivial to implement in userland should be published as npm module and not belong to core.
  • For practical usage, io.js users want to have standardized and easy way to consume core APIs that are required on most common use cases.
  • The minimal core API provided by io.js is not sufficient for modern use cases. Promise-based API and readable-stream are some of such use cases.
  • Promisifying callback-based API is trivial, but writing code like Bluebird.promisifyAll(require('fs')) is ugly and non-standard.
  • Having different ways of consuming promisified API is confusing and painful. The cognitive overhead of having to decide such trivial thing is too much.
  • What user want is really an authoratative way of consuming Promise-based core API. The motivation is the same as moving readable-stream to core as discussed in #55.
  • Authoratative/standardized API and implementation is overseen by the same io.js core community instead of individuals or companies. It makes it easier to trust and learn than using random npm modules.
  • The same principle could be applied to other userland libraries that are common enough to be standardized but not low-level enough to be included in core.

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.

from node.

pluma avatar pluma commented on April 28, 2024

-1 for the time being, +1 for revisiting this request in six months or so.

from node.

spion avatar spion commented on April 28, 2024

@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.

from node.

benjamingr avatar benjamingr commented on April 28, 2024

@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.

from node.

cscott avatar cscott commented on April 28, 2024

@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.)

from node.

benjamingr avatar benjamingr commented on April 28, 2024

@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.

from node.

spion avatar spion commented on April 28, 2024

@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.

from node.

mikolalysenko avatar mikolalysenko commented on April 28, 2024

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.

from node.

benjamingr avatar benjamingr commented on April 28, 2024

@mikolalysenko - devil's advocate: it is very values or to have good defaults

from node.

spion avatar spion commented on April 28, 2024

@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)

from node.

gx0r avatar gx0r commented on April 28, 2024

@spion Interesting. Does "npm dedupe" help in that case, or is that not ideal?

from node.

spion avatar spion commented on April 28, 2024

@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 :)

from node.

jmar777 avatar jmar777 commented on April 28, 2024

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.

from node.

jmar777 avatar jmar777 commented on April 28, 2024

@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. :)

from node.

rlidwka avatar rlidwka commented on April 28, 2024

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?

from node.

drewhamlett avatar drewhamlett commented on April 28, 2024

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.

from node.

jmar777 avatar jmar777 commented on April 28, 2024

@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.

from node.

gaearon avatar gaearon commented on April 28, 2024

@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.

from node.

domenic avatar domenic commented on April 28, 2024

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

from node.

gaearon avatar gaearon commented on April 28, 2024

@domenic Does this match what Bluebird is doing, or do I miss some detail?

from node.

benjamingr avatar benjamingr commented on April 28, 2024

@gaearon given that adding onUnhandledRejectionHandled in Bluebird was @domenic 's idea that makes sense :P

from node.

gaearon avatar gaearon commented on April 28, 2024

Ah, never realized this. 👍 It's awesome.

from node.

benjamingr avatar benjamingr commented on April 28, 2024

@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.

from node.

darrenderidder avatar darrenderidder commented on April 28, 2024

@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.

from node.

tracker1 avatar tracker1 commented on April 28, 2024

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.

from node.

phpnode avatar phpnode commented on April 28, 2024

@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())

from node.

tracker1 avatar tracker1 commented on April 28, 2024

@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.

from node.

phpnode avatar phpnode commented on April 28, 2024

@tracker1 bluebird proves that promises can be almost as fast as callbacks, the idea that promises have to be "slow" is damaging imho.

from node.

gaearon avatar gaearon commented on April 28, 2024

@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.

from node.

YurySolovyov avatar YurySolovyov commented on April 28, 2024

@phpnode they can even be faster

from node.

benjamingr avatar benjamingr commented on April 28, 2024

@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:

  • Memory problem is not an issue and can be solved effectively by an engine aware implementation. For example check out bluebird which consumes very little memory and does not cause GC issues. V8 has an old object heap and a fast heap and Bluebird almost never gets to the old heap - GC works and it works well.
  • Composition problem - non-done lists - If you have a list and you don't know how many items you have don't use a promise use a queue or an event emitter. All the memory concerns simply do not happen since the promise implementation is engine aware. Promise implementations stitch stack traces and you know exactly where the errors are. All problems mentioned here happen with callbacks anyway.
  • Parallelization problem - the db synchronization example is solved by libraries by using Promise.using in bluebird - it's a hard problem (same with callbacks) but you generally use the disposer pattern to address it.
  • The atomicity problem - addressed usually by promise cancellation, but I don't see what this has to do with promises. If your use case is not a nodeback-like case (that is "called once with value") you shouldn't be using a promise.

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.

from node.

rvagg avatar rvagg commented on April 28, 2024

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

from node.

cscott avatar cscott commented on April 28, 2024

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.)

from node.

arcanis avatar arcanis commented on April 28, 2024

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.

from node.

teamrun avatar teamrun commented on April 28, 2024

node reflections...
Suggesting that promises should go back into core

from node.

kiddkai avatar kiddkai commented on April 28, 2024

-1, it just one of the patterns to resolve the callback hell issue. And there're many other way to achieve the same goal.

from node.

zensh avatar zensh commented on April 28, 2024

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 ...
});

from node.

leecade avatar leecade commented on April 28, 2024

co 👍

from node.

hashseed avatar hashseed commented on April 28, 2024

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

from node.

gx0r avatar gx0r commented on April 28, 2024

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.

from node.

rvagg avatar rvagg commented on April 28, 2024

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.)

from node.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.