Skip to content
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

Feature/byop #244

Closed
wants to merge 3 commits into from
Closed

Feature/byop #244

wants to merge 3 commits into from

Conversation

taxilian
Copy link

This allows a user to provide their own promise library; this is useful as there are libraries which offer benefits over the ES6 Promise object but are also API-compatible (or could be easily made to be so). One particular benefit of using the same promise is that some libraries (notably q and bluebird) support long stack traces across multiple callbacks which is useful for debugging; however, when using a different promise in the middle (or particularly the end) of the chain breaks this functionality.

This is referred to in some libraries as Bring Your Own Promise (BYOP) and is very important to those of us who use third party promise libraries. I have copied the promise unit tests to a byopromises unit test file which performs all of those tests with bluebird set as the Promise type and verifies that it works.

@cesarandreu
Copy link

If you want to use the same Promise library everywhere, why not overwrite global.Promise?

@joshbeam
Copy link

@cesarandreu I could be wrong, but it feels like setting a particular promise library for co should be a separate implementation detail from overwriting the entire global ES6 promise (which is what this PR seems to address specifically). Thoughts?

@taxilian
Copy link
Author

I agree with @joshbeam; while there may be times when overriding the global makes sense, generally I prefer to avoid overriding globals in order to prevent problems with minor implementation detail differences and modules or libraries which may not have specific unit tests to test alternate promise libraries, etc. I added unit tests to this PR to make sure it would work with another Promise library, but other libraries which use ES6 promises may not have that.

I submit that overriding a global should not be the required way of doing something that was, in actuality, so simple to implement. It does not make the code harder to read or to understand, it does not add a significant burden for code maintenance, and it does prevent the need to follow what I consider to be a dangerous practice -- overriding global built-in types.

@@ -47,7 +64,7 @@ function co(gen) {
// we wrap everything in a promise to avoid promise chaining,
// which leads to memory leak errors.
// see https://github.com/tj/co/issues/180
return new Promise(function(resolve, reject) {
return new coPromise(function(resolve, reject) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure this syntax will work for whatever promise library the user wants? If not, should there be some sort of whitelist, or do we want it to just throw the error it would normally throw if the promise library for whatever reason doesn't work (i.e. fail loudly, but without a specific error message saying "this promise library doesn't support this syntax").

Only reason I bring this up is because this seems to have only been tested with bluebird.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very good question; my reasoning for keeping this is twofold:

  1. The two promise libraries I've looked at (Q and bluebird) both support this method, though Q requires you to use Q.Promise (and yes, I've tested it and it works)
  2. It is trivially easy to make a wrapper around any promise library which will support this interface; some libraries may require that anyway in order to support all of the specific function names which co uses. I figure this is fair, though, since co uses the ES6 standard so any promise library wishing to use it will just need to either support that interface or have a wrapper which allows it to.

@taxilian
Copy link
Author

@joshbeam valid point on the comment format; fixed.

@taxilian
Copy link
Author

This same basic pattern is used in mongoose, in case that helps you feel any more comfortable with it =]

@ruimarinho
Copy link

@taxilian how is this different from #226?

@taxilian
Copy link
Author

taxilian commented Oct 1, 2015

Interesting; I thought I'd looked through the pull requests and missed that one. I believe they are functionally equivalent; I guess the only real difference is in a few of the details of implementation and that I provided tests to go with this.

Given how long the other pull request has been waiting for review, do I take that to mean that I should give up and use his fork? That would probably work for me. I don't care which I use, but I need the functionality.

@ruimarinho
Copy link

I think the use case is valid and I'm experimenting with co-use right now. Considering that the original PR hasn't received any feedback from the maintainers yet, I'm not sure if it's going to be a welcomed feature or not.

@tj
Copy link
Owner

tj commented Oct 2, 2015

I'm meh on it personally, I think having something like this is cleaner in a sense, but at the same time it would be such a massive pain to go set the promise lib to something new for every single package out there in your app. The polyfill route is reasonable in that sense I suppose. Ideally co doesn't even exist (with async/await etc) so I probably wouldn't bother

@mathieug
Copy link

mathieug commented Mar 6, 2016

Need! 👍

@mathieug
Copy link

mathieug commented Mar 6, 2016

I like the way mongoose implements it: http://mongoosejs.com/docs/promises.html#plugging-in-your-own-promises-library

@tj
Copy link
Owner

tj commented Mar 6, 2016

Forgot to close. I'm firm on not supporting arbitrary Promise implementations. Libs like bluebird et al should work with promises, not implement their own (or optionally act as a polyfill as well). If you need a polyfill, then use a polyfill :).

@tj tj closed this Mar 6, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants