-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
use Q.js #1699
Comments
How do you see this? Instead of mpromise? |
yep but v4 On Saturday, October 5, 2013, Refael Ackermann wrote:
Aaron |
After all I've done for #1732 this seems like the next logical step :) |
I might even find a way to use Q instead of |
@aheckmann, I need you guidance.
|
Hi guys, I love the work you've been doing on adding promise support throughout Mongoose! I've recently understood and started using Promises and it has been just a way better experience than plain simple callbacks. Can I ask you what is the motivation behind choosing Q.js? I've been using RSVP and I've loved it for its simplicity. (I am sorry if that is a dumb question) I would also love to help you out in this transition, I just need some better understanding of the Mongoose codebase. Cheers, |
we ideally should use any promise library we want and allow users to specify it as well. As long as it conforms to PromisesA+ I don't really care. |
Q is the most starred promise library on GitHub and a rich implementation of the PromisesA+ plus the fact that AngularJS uses Q has people using Q in the frontend. I think the MEAN stack would rock if mongoose used Q as well. Using the same promise library for the frontend and the backend will make the difference between both programming models much shorter. +1 on this issue. |
+1 for when.js |
I would strongly advise to pick bluebird over q. I've been doing NodeJS for a couple of years, and switching from q to the very well-crafted bluebird has been a really pleasant experience. The API is far superior and the performance is unmatched. Regarding performance, have a look at this article.
|
Why not when.js? |
+1 for when.js |
Actually, we ideally should use the native promise implementation and a simple shim for Node versions without support. According to a comment by tjfontaine from 6 days ago, native promises are in master. So I think they will be available in the next release. Mongoose doesn't seem to be needing any of the fancy features most promise libraries give you and should be perfectly fine with the native methods |
+1 for native promises |
I just discovered native promises in node 0.11.13 (behind --es-staging), and I'm playing with making |
@refack Greatly appreciated :) I'm not sure what |
@bernhardw, thanks for the tip. Very progressive of the V8 team (adding symbols to the global namespace). I think I hear the sound of KLOCs creaking and breaking :) |
Native promises are considerably slower than Bluebird promises. Heck, with newest Node, Bluebird with generators is now faster than callbacks. |
P.P.S - V8 flags and their meanings |
Is https://github.com/domenic/promises-unwrapping an example of native promises spec? I really like Q and bluebird, but with native promises are around the corner, it may be beneficial to stick to native's conventions but offer a polyfill for older node versions. Regarding polyfill libraries, what are our options? Is https://github.com/jakearchibald/es6-promise a good candidate? It seems more active than mpromise and doesn't require additional dependencies. |
On top of normal es6-promise, rsvp seems to have some cool error bubbling features. https://github.com/tildeio/rsvp.js#error-handling. One of the major pain points with promises (native or not) is tracking down errors. In fact, if I had an adequate way around that, I'd be open to settle for something that wasn't fully native / following barebones es6 promise implementation. |
Here is another link I think is a good read: https://github.com/spion/async-compare http://dailyjs.com/2013/10/04/bluebird/ "One of the tools Petka mentions for verifying the quality of the project was async-compare by Gorgi Kosev. This project aims to compare async patterns based on their complexity, performance, and “debuggability”. The stack traces generated by libraries like Bluebird and Q are captured and curated, so async-compare can be used to measure the distance between the function that created the error and the error in the stack trace. This is useful because debugging asynchronous code is notoriously difficult." Promises are still something I'm wrapping my brain around, especially the debugging aspects of it. Does the choice of library really matter when it comes to debuggability? I find my current understanding of errors with promises is vague at best. |
You might find this recent comment regarding bluebird vs. native from Petka interesting. Would it be possible to somehow configure the Promise provider used by a mongoose instance (like passing |
btw in next bluebird version it promisifyAll has been steroid-boosted and will be able to promisify mongoose (and a lot of other modules) in one line with https://github.com/petkaantonov/bluebird/blob/2.0/API.md#promisification |
So are you going to migrate to |
@vkarpov15 the answer is simple: Allow library authors to pass the promise constructor into the library (or a compatible interface) - that way anyone can use their favorite implementation with its quirks and benefits and you can stay uncoupled to any promise implementation. |
That would be great if promise constructors had compatible interfaces. Suppose you have:
For
For
And for
So its not quite as simple as saying |
Because that's the standard. Q implements the same standard in |
@vkarpov15 I'm with petka here, there is a standard and libraries like Q follow it (with
|
var P = require('mpromise');
function PromiseConstructor(resolver){
var p = new P;
if(typeof resolver !== "function") throw new TypeError("Promise resolver must get a function");
try{
resolver(p.fulfill.bind(p), p.reject.bind(p));
} catch(e){
p.reject(e);
}
return p; // also, resolving with multiple args is not allowed and is a spec violation...
} |
@benjamingr If resolver is not a function the exception needs to be thrown synchronously |
@whitecolor FWIW, you can promisify mongoose in one-line with |
mpromise does implement a standard. While I do love ES6, its still just a draft of a standard rather than a standard. However, I was wrong about Q's inconsistency, so this could be implemented in theory, so thanks for pointing that out :) It will require a lot of very messy changes because the "promise constructor with executor" syntax is nasty - one of the many reasons why I like mpromise. |
@petkaantonov thanks, will try it |
@vkarpov15 the A+ standard just specified resolution and The construction specification is here https://github.com/promises-aplus/constructor-spec , it's older. You don't even have to require it you can ask people to provide a different resolution API and write adapters as long as you let them pass their own implementation. |
I meant a construction standard, not any standard. And ES6 promises are nailed down. Awkwardness of revealing constructor pattern should not be a big deal because it's trivial to implement the deferred api on top of it: function deferredFactoryFor(PromiseConstructor) {
return function() {
var ret = {};
ret.promise = new PromiseConstructor(function(resolve, reject) {
ret.resolve = resolve;
ret.reject = reject;
});
return ret;
};
}
var bluebirdDefer = deferredFactoryFor(require("bluebird").Promise);
var QDefer = deferredFactoryFor(require("q").Promise);
var RSVPDefer = deferredFactoryFor(require("rsvp").Promise);
var WhenDefer = deferredFactoryFor(require("when").Promise);
var NativeDefer = deferredFactoryFor(Promise);
var mdefer = ???? |
Yeah I agree, its easy enough to add a wrapper around it. Thanks for the insights. |
+1 |
There seems to be a larger issue in the javascript community surrounding promise libraries and libraries that expose promisified interfaces. We've conflated the functionality of providing a future value (specified in the A+ standard), and syntactic sugar for easily working with those future values. One big problem that this creates is that, as a library author, you basically can't use anything but the naked A+ promise in your code if you're going to allow users of your library to swap out the promise implementation. It would be nice to take a little time and perhaps think through how these two concerns could be elegantly separated. @petkaantonov any ideas around this? Promisify has worked well for me, but it seems like there could be a better way... |
I think you're looking at this the wrong way - you can expose whatever interface you'd like as long as it conforms to promises/A+ it will be easy to consume it to the outside ( There really isn't a huge reason to allow any library to be used - it's enough to use a fast good library like bluebird most of the time - as long as it's not something like mpromise that swallows all errors it's all good. |
The reason that most people want a library to support their favorite promise interface is, 99 times out of 100, because they prefer/are used to the syntactical sugar that library adds to the base A+ interface. I have seen performance used as an argument by some users to get their favorite library chosen, but it's usually just a red herring tactic to get what they really want: the interface of their favorite promise library. This syntactical sugar is tightly bound to the A+ interface of every promises library, which makes it very difficult for a library author to expose a promise-based interface, and support all of their user's favorite promise library sugar. There are ways around this, but the ones I've seen have been brittle (promisifyAll) or are just so messy it's not worth doing (manually wrapping the promises returned by a library). A lot of these discussions would go away if there was an elegant convention to separate these concerns, to allow both library authors, and library consumers to use their preferred syntactical sugar. I'm not convinced that having a promise library convert a CPS interface is the best way to accomplish this. This all reminds me of libraries written in C++ but that expose C bindings because the C++ ABI was never standardized enough to allow other languages to indiscriminately import C++ DLLs. |
Why is promisifyAll brittle? I've found it rock solid and working in wrapping every library I want. If there is a case where it isn't working there's always To be fair - I don't see the huge value in allowing swapping of the promise implementation - I'd just pick the fastest one that's easiest to work with or not at all and do wrapping - see my comments here: #2688 (comment) |
Re: You may not see the value because the promise library you use (which is actually the one I prefer as well) is currently the performance leader and has a list of excellent features, but that could change. And then what, everyone change to the then fastest library? And really, the syntactical additions do not a fast promise library make. In fact, it's very possible that native promises will outstrip even Bluebird in speed if the implementers do a good job with the native impl. Finally, I hope that we can agree that "easiest to work with" is incredibly subjective and doesn't really provide any value in the discussion on what we're trying to accomplish here. |
My 2 cents - if you really care about shaving a couple microseconds of CPU time by using bluebird vs RSVP or something, you're not going to be using promises anyway. Frankly, if that level of optimization matters to you, you probably shouldn't be using node at all. Promises are all about syntactic sugar and writing code that's more durable and easier to maintain. Of course that is a function of which promises library the user has most experience with, which is why I see the value of letting people specify their favorite promises library. |
Why? There is very little if at all overhead. There are actual real world workloads that are impossible to handle with mpromise but are possible (and done with bluebird). If you have 5000 connections to the client and a flow chain of a client's request is |
As a long time mongoose user, I don't really understand why mongoose 4 is using an exotic (thus probably quite slow) promise implementation over native ones or bluebird (clearly the best pick for the past couple of years)? Why not allow every end user to choose it's library as long as it comply with the A+ spec? something like |
@mgcrea for one thing you're using free software ;) I'm sure pull requests are welcome - and as mentioned before using bluebird with Mongoose is already a one-liner |
@benjamingr, are you referring to If there is consensus towards removing the tightly coupling between mongoose and mpromise, I would gladly spend some time to craft a potential PR, but for now, I need a better understanding of the reasoning behind the mpromise pick before acting and wasting everybody's time. |
People asked for promises support and Mongoose is quite a mature library now over 4 years old- mpromise was chosen because it looked like a good way to add promise support at a time. There was no bluebird when the choice was made and there certainly were no native promises. |
@benjamingr I though mpromise was picked recently, but it looks like it just only really spun out of mongoose core as a separate library. Thanks for the explanation. |
@mgcrea that's the whole point of #2688. We hope to be able to support arbitrary ES6 promise libraries in the next couple months. Also, @benjamingr is right, mpromise has been a part of mongoose for quite a long time. We kept it in as a "good enough" solution while we worked on issues we believed to be more pressing. Re-addressing promises is an immediate priority now though. |
No description provided.
The text was updated successfully, but these errors were encountered: