Skip to content

Feature Request: Every async function returns Promise #11

Description

@rdner

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.


Activity

  1. jonathanong commented on Nov 29, 2014

    @jonathanong
    Contributor

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

  2. rdner commented on Nov 29, 2014

    @rdner
    Author

    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.

  3. jonathanong commented on Nov 29, 2014

    @jonathanong
    Contributor

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

  4. rdner commented on Nov 29, 2014

    @rdner
    Author

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

  5. TJkrusinski commented on Nov 29, 2014

    @TJkrusinski

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

  6. darrenderidder commented on Nov 29, 2014

    @darrenderidder

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

  7. indutny commented on Nov 29, 2014

    @indutny
    Member

    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.

  8. Qard commented on Nov 29, 2014

    @Qard
    Member

    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.

  9. vkurchatkin commented on Nov 29, 2014

    @vkurchatkin
    Contributor

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

    In what way?

  10. medikoo commented on Nov 29, 2014

    @medikoo

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

  11. Qard commented on Nov 29, 2014

    @Qard
    Member

    @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

  12. vkurchatkin commented on Nov 29, 2014

    @vkurchatkin
    Contributor

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

  13. medikoo commented on Nov 29, 2014

    @medikoo

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

  14. Qard commented on Nov 29, 2014

    @Qard
    Member

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

  15. defunctzombie commented on Nov 29, 2014

    @defunctzombie
    Contributor

    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.

  16. 306 remaining items

  17. bmeck commented on May 14, 2015

    @bmeck
    Member

    @arcanis it is definitely a memory and cpu hit to move to them, anything that causes those in core should be very carefully regarded.

  18. arcanis commented on May 14, 2015

    @arcanis
    Contributor

    From my point of view, Io.js is, more than just a Node fork, a way to playtest the ES6 features (it's more complex than that, of course, but you get the gist).

    ES6 promises are not yet another hype: they are in the language, they will stay, and are now the standard way for a js program to notify that a task has been completed. Of course, their performances are not yet on par with regular callbacks, how could they be? The engine implementations are still fresh, and cannot yet compare with something whose every possible optimization has been tried (I guess :).

    Anyway, I'm still talking about perfs but my point is unrelated to them: promises being standard, it seems to me that we have nothing to debate except "ok, how to get them in the standard Node library without breaking BC?". The discussion "should we include them in the langage? are they a good enough solution?" has already been done by the ecmascript commitee. Now, it's up to the library authors to use them and give feedback.

    As a side note, look at the C++ standard library. Despite C++ being almost exclusively used for its perfs, the standard library is focused on being portable and relatively easy to understand. The perfs come only third. That's imo how a standard library should be designed : it should closely follow the language constructs, so that a beginner can start hacking without much second thought. Then, once the need arise, switch to a specialized library, focused on perfs.

    By keeping the callback API as the only Io.js API, we would only force every Io.js developer to live with a constant premature optimization.

  19. Fishrock123 commented on May 14, 2015

    @Fishrock123
    Contributor

    From my point of view, Io.js is, more than just a Node fork, a way to playtest the ES6 features (it's more complex than that, of course, but you get the gist).

    In reality, not really.

    What we can do in io.js (or in the converged node project) is to put things like this behind flags for testing, if it can be done reasonably. (Like the workers impl)

  20. benjamingr commented on May 14, 2015

    @benjamingr
    Member

    @arcanis

    As a side note, look at the C++ standard library. Despite C++ being almost exclusively used for its perfs, the standard library is focused on being portable and relatively easy to understand. The perfs come only third.

    The whole point of C++ is that it's a zero cost abstraction and you don't pay a performance penalty for features you don't use. This statement is in complete contrast to everything I've ever read about C++ and/or lectures I've heard.

    Check out "B. Stroustrup: The Design and Evolution of C++. Addison Wesley, ISBN 0-201-54330-3.
    March 1994": What you don’t use, you don’t pay for (zero-overhead rule).

    By keeping the callback API as the only Io.js API, we would only force every Io.js developer to live with a constant premature optimization.

    No one is suggesting that, promises are already decided - we're just waiting for them to be ready for prime time.

  21. tracker1 commented on May 14, 2015

    @tracker1

    Honestly, I don't think we should remove any of the existing callback implementations, too much existing structure relies and/or builds on them. That said, Promises are here to stay, and will become the defacto way to build stuff... Moving forward, async/await will expand this much, much farther.

    import u from '../../../utility';
    export {processOne as default}
    
    async function processOne() {
      let [q,table,index] = await Promise.all([
        u.getQueue('stowListing'),
        u.getTable('listing'),
        u.getEsIndex('listing')
      ]);
      var msg = await q.one();
      if (!(msg && msg.value)) return null; //no record in place
    
      var {accountId,listingId} = msg.value;
      var data = (await table.read(accountId,listingId)).dataObject;
      await index.upsert(listingId,data);
      await q.done(msg);
      return listingId;
    }
    

    I won't even begin to describe what that workflow would look like without Promises. This is code I am using today using BabelJS... my sincere hope is that I'll be able to do this natively in iojs/node within a year, without having to transpile.

    Using callback patterns directly would be a lot more work, a lot more verbose, and a lot more prone to error. Regardless of the performance issues... code that works, is better than code that is broken and/or more prone to errors. For now, there's mz, which wraps internal libraries in promisified versions... for that matter, I setup bluebird as my global promise implementation because it tends to work better, and have more features than the native version... all of that said, striving for this in core is a good idea.

  22. greim commented on May 14, 2015

    @greim

    Hasn't the window of opportunity long since closed on using an import switch, given how much transpiler-supported ES6 code already exists in the wild? It would lock people into their transpilers forever.

  23. vkurchatkin commented on May 14, 2015

    @vkurchatkin
    Contributor

    @greim people who want to migrate from transpiling would have to replace import of builitns with require. it's not that bad, actually. Or we can publish a module that simple re exports old APIs, so that people could simple change import fs from 'fs' to import fs from 'old-node/fs'

  24. CrabDude commented on May 15, 2015

    @CrabDude

    @greim No, not really. It's really only an issue for published packages, and publishing packages with import. For application developers, it's as simple as replacing import with require in application code, but that window will likely close in 6 months.

  25. greim commented on May 15, 2015

    @greim

    I'd still argue for callback detection for a few reasons:

    • The behavior change is triggered by changing how you call the API in question, rather than how you use an unrelated language feature.
    • Popping the errback off the argument list moves the action to the return position, which has a certain symmetrical feel to it.
    • Errbacks aren't going away, so some sort of quirk will be left floating around in node as a result of this; there's no way around it. The nature of the quirk might as well itself be descriptive of the reason for its existence.
    • It can be done with negligible impact on performance.
    • It leaves the user free to choose.
    • While it would almost certainly break someone's code somewhere (every major node version does), it should be extremely rare, and wouldn't otherwise lock large swaths of folks out of upgrade paths pending code rewrites. Node is already evolving so fast that avoiding schisms (ala python 2/3) should be on everyones' worry list. We don't know which hair will break that camel's back.

    Anyhow, there's my 2¢, carry on.

  26. Temptin commented on May 30, 2015

    @Temptin

    I agree with dual functionality; either returning promises or using callbacks depending on how the functions are called. The only problem is how freakishly slow V8's "native" promises are. They are written in JavaScript and aren't even close to Bluebird's performance. So until the performance issue with promises is resolved, I don't see any value in changing node to support them. They're just too slow right now and would be a hindrance to Node's performance.

    Would be interesting if someone with contacts at Google could find out if they're going to improve their promises implementation. If not, then I suggest avoiding promises like the plague.

  27. ChALkeR commented on Jun 5, 2015

    @ChALkeR
    Member

    Was the fact that v8 Promise implementation is slow ever raised on the v8 issue tracker? I can't find a corresponding issue, either open or closed.

    I assume that's one of the blockers of promisifying core.

    And one other thing that I don't get: why are v8 promises implemented with mixed native/js code, when pure js implementations are faster?

  28. benjamingr commented on Jun 5, 2015

    @benjamingr
    Member

    @ChALkeR they are very well aware of the issues - see Domenic's comments here

  29. Fishrock123 commented on Jun 15, 2015

    @Fishrock123
    Contributor

    If people are interested, discussion should be moved to the NG repo: https://github.com/nodejs/NG/issues

    Closing & locking this because it's mostly bikesheding that no-one has the time to read though. @rvagg's comment in the OP still stands.

  30. locked and limited conversation to collaborators on Jun 15, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    discussIssues opened for discussion and feedback.feature requestIssues requesting new Node.js features.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions