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
[fixed]The .then() function is not compatible with Promises #722
[fixed]The .then() function is not compatible with Promises #722
Comments
👍 |
1 similar comment
+1 |
I'm pretty sure the intent was not to add a full on promise implementation. Promises A+ spec documents the use of thenables, objects with Q(thenable).then(...).fail(...).done(); |
Yes, we did not actually intend to add full promise because I don't want to bloat the library for everyone for what I perceive to be a marginally (if not worse) api. We know this is not full promises and is not meant to be. If there is a solution you have that works better but is not requiring full promises to be present. ping @matthewmueller |
I've suggested using global
Is that not satisfactory? |
Yep, for additional context, the most recent PR aims to resolve #230. That was the only intent of the PR. It was not to add promise support. Personally, if what you suggested works properly, all existing tests pass and you include a small catch implementation, I think that would be better that what was implemented in 1.3. Also, if I'm not mistaken, your solution would require everyone to be running node 0.12 or io, right? |
It would not require node 0.12, but it would require a polyfill (e.g. you'd need babel or |
Yep, so it would require Node 0.12 or a polyfill. And the polyfill would need to be present on the browser implementation as well (for IE). I tend to agree with @defunctzombie on this that it's a marginal API improvement for a non-trivial increase in file size (17.952 kB minified). Though I do agree and sympathize that the |
Yeah, please don't roll a Promise polyfill. I'd have to consider moving all my projects away from superagent at that point. It's a good amount of bloat, and we already have big projects using Q and superagent together. I'm sure a lot of other users would echo this sentiment. Thenables are fine, they should simply be documented as such. |
Heh. Definitely document the heck out of this. But at this point I'm moving away from projects that are using just thenables in favor of ones that use promises. |
@matthewmueller Where do you take that 17KB from? I think superagent bundling promises implementation would be a mistake, and a serious downside. Where necessary, I already have a promise polyfill in my code, and I don't want a second one. It's wasteful and could cause bugs (I've ran into such problems when libraries had their own copies of the Q library, but Q breaks in subtle ways if there's more than one copy). I'm assuming that nobody would be interested in using the |
Are you assuming that when people use promise libraries, they add them to the global namespace? If so, that is sort of a silly assumption. |
Here: https://github.com/jakearchibald/es6-promise/blob/master/dist/es6-promise.min.js
This is an example of where a |
es6-promise currently overwrites native promise implementation due to (IMHO tiny and irrelevant) bugs in v8, so bundling of it in superagent would cause negative side-effects.
|
Yep, the point isn't about compatibility though, it's about file size. We wouldn't be having this discussion if either, Promises were implemented everywhere or we can implement an extremely light-weight version of promises that weighs in at like 1-3Kb minified. The PR implemented added 4kb unminified and since a lot of it is repeated, I suspect gzipped with the rest of the file, it basically goes away. |
I think you're wrongly assuming that you need to implement promises. The way I see it it's something you integrate with, not something you provide. Bundling promises with superagent would be like bundling v8 with superagent, in case somebody wants to use the JavaScript library, but doesn't want to install a JavaScript VM. |
I think you are wrongly assuming that everyone who wants to use promises exposes a What are your reasons for pushing this? Is there some upside I'm missing that isn't already easily achievable? I can only think of down sides. |
Okay, so if I'm understanding what you're saying correctly, you're suggesting something along the lines of... if ('undefined' != typeof Promise) {
Request.prototype.then = function(resolve, reject) {
var self = this;
return new Promise(function(resolve, reject){
self.end(function(err, res){
if (err) reject(err); else resolve(res);
});
})
.then(resolve, reject);
};
} If that's the case, then I don't really care much either way since it doesn't add much bulk and yield will work in environments that promises work. Not sure how @defunctzombie feels about that, but I'd welcome your PR. |
I thought the original intent was to turn the request object into a "thenable" so any promise library with coercive functionality could turn it into a promise. So for native promises, it would look like: var reqPromise = Promise.resolve(superagent.get('/whatever'))
.then(something, otherThing)
.then(null, blahBlah)
... is this not the original intent? why force usage of native promises in browsers that support them? |
@kahnjw I think the concept of thenables exists primary for interoperability between Promise-compliant libraries. It is possible to convert thenable to a fully-functional Promise, but it isn't convenient, and superagent's implementation is not functional enough to start a promise chain without explicit conversion. I try to avoid thenables as much as I can, because they don't give guarantees that Promises have (e.g. that callbacks are run on the next tick) and can cause bugs. In Superagent 0.13 case this happens to work thanks to casting:
but if you refactor the code to swap the first two functions, it'll unexpectedly break in a weird way:
and while it's possible to fix it with an explicit |
I just don't understand the desire to make this function reliant on a global |
The global And the desire for it is to have a robust API without footguns. The faux promise stopgap thing:
I suppose you're not "sold" on Promises, but please understand that for somebody who's using them heavily Superagent's faux solution is not only insufficient, but even harmful. v0.12 used without some glue code would clearly fail with "then is undefined", but v0.13 is now worst of the both worlds: without diligent wrapping in |
I think this is sacrificing compatibility for convenience. Doing this would break thenable coercion methods in most promise libraries on environments like Node 10, and on browsers like IE10, IE11 and Safari 6. I agree that your suggestion is cleaner, better, and preferable, but only marginally and if you assume everyone uses FireFox or Chrome. The downside is pretty bad for consumers relying on Promise libraries that don't polyfill Promise. A thenable is a thing. It is in Promise A+ spec. Yes it is a stopgap solution until ES6 Promises are used everywhere. The javascript community is simply not there yet. |
It doesn't have to break compatibility if the faux solution is used as a fallback. |
Since v1.1.0, SuperTest ships a version of SuperAgent with "thenable" support; that is, a then method which provides minimal interop with Promise libraries but does not provide full then semantics. See ladjs/superagent#722 and ladjs/superagent#726 for context. Since SuperTest's maintainer is entirely unwilling to support promises, we'll continue to maintain this library for those who want `.then()` to return a real promise.
Interesting discussion: I don't think there is any negative impact on using The question is rather client-side, where we might want to include the Promise polyfill for convenience but as @pornel stated, we don't want to overbloat if people already rely on external polyfills. Usage wise, I think we are at a stage people are familiar with promises, especially since the rise of Node 4.x. |
If people are averse to depending on a global Promise (I don't think that's a big deal since it's part of the language - not DOM - spec now), what about adding a mechanism for users to supply some factory function for producing promises? That way superagent has no implementation of promises itself (or half an implementation as it stands), and consumers can use their favourite promise implementation or the global Promise type. Currently I find the |
A thenable without chaining is no different than supplying a callback as an argument to the method. It serves no purpose other than to fool the developer into thinking it's a fully-implemented thenable. If you don't want to adhere to the promises/A+ spec, then remove the then function. |
This is fixed in 2.0.0 |
@pornel I've been reading your comments throughout. I'm with you all the way. These guys must not use Promises. I'm battling to get my superagent stuff promisified so to not manually wrap all of my api methods in promises. I don't see how anyone can argue against using global Promise either; It's an ECMA standard and the previous superagent implementation was pointless. Might as well use the callback. |
Looks like version 2.0 is the answer. |
so is it now possible to this ?
|
No, |
thanks |
The faux
.then()
function added in 1.3 completely misses the point of promises and breaks even in simple cases.Should print
1
, but throws an unhandled exception.Please don't try to reimplement promises — just enable use of a correct library.
I suggest:
The code above assumes that promises are either supported natively (already the case in majority of browsers and even Node 0.12) or polyfilled by the user (which is a common practice, e.g. ES6 transpilers do it).
The text was updated successfully, but these errors were encountered: