Skip to content

Instantly share code, notes, and snippets.

@cowboy
Last active August 29, 2015 13:56
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cowboy/9281390 to your computer and use it in GitHub Desktop.
Save cowboy/9281390 to your computer and use it in GitHub Desktop.
Man, jQuery Deferreds annoy the fuck out of me.
// When a jQuery deferred is resolved with a single value, the arguments to
// the .then callback are the same as when .then is called directly on the
// deferred or on $.when(deferred) AND ALSO $.when(deferred, deferred).
var dfd = $.Deferred().resolve([1, 2, 3]);
dfd.then(function(a) {
console.log('[1a]', a); // [1, 2, 3]
});
$.when(dfd).then(function(a) {
console.log('[2a]', a); // [1, 2, 3]
});
$.when(dfd, dfd).then(function(a, b) {
console.log('[3a]', a, b); // [1, 2, 3] [1, 2, 3]
});
// When a jQuery deferred is resolved with multiple values, the arguments to
// the .then callback are the same as when .then is called directly on the
// deferred or on $.when(deferred) BUT NOT $.when(deferred, deferred).
var dfd = $.Deferred().resolve(1, 2, 3);
dfd.then(function(a, b, c) {
console.log('[1b]', a, b, c); // 1 2 3
});
$.when(dfd).then(function(a, b, c) {
console.log('[2b]', a, b, c); // 1 2 3
});
$.when(dfd, dfd).then(function(a, b) {
console.log('[3b]', a, b); // [1, 2, 3] [1, 2, 3]
});
// I mean, I get it. You want $.when(deferred) to be idempotent. Is that the
// right fancy word? Whatever, close enough. And spreading all those values
// across the $.when(deferred, deferred) callback would be insane. Arrays make
// sense there. But why then spread those values across the deferred.then or
// $.when(dfd) callback? Because it's magicsexy?
// Because jQuery Ajax requests are resolved with multiple values instead of
// with a single array value, the arguments to the $.when(req, req) callback
// behave very differently than the arguments to the req.then or $.when(req)
// callback. THIS REALLY CONFUSES PEOPLE. SERIOUSLY, I SEE IT ALL THE TIME.
var req = $.ajax('/');
req.then(function(resp, status, obj) {
console.log('[1c]', resp, status, obj); // response 'success' jqXHR
});
$.when(req).then(function(resp, status, obj) {
console.log('[2c]', resp, status, obj); // response 'success' jqXHR
});
$.when(req, req).then(function(a, b) {
console.log('[3c]', a, b); // [response, 'success', jqXHR] [response, 'success', jqXHR]
});
// And because the $.Deferred() factory builds new deferred objects from
// scratch without any of the internal mechanics or some kind of prototype
// exposed, it's impossible to, say, override the Deferred resolve / reject
// method with one that converts multiple values into an array before
// actually resolving / rejecting.
// Here's a "plugin" that works around this annoyance by throwing away
// the extra values: 'success' & jqXHR, just leaving the response.
$.makeAjaxResultLessShitty = String;
var req = $.ajax('/').then($.makeAjaxResultLessShitty);
req.then(function(a) {
console.log('[1d]', a); // response
});
$.when(req).then(function(a) {
console.log('[2d]', a); // response
});
$.when(req, req).then(function(a, b) {
console.log('[3d]', a, b); // response response
});
// Anyways, this all begs the question:
// WHY RESOLVE JQUERY DEFERREDS WITH MULTIPLE VALUES?
// (Arrays work pretty darned well)
@louisremi
Copy link

@dmethvin's idea of a slightly different API with a better name is still a good solution to the problem. $.ajax could later be marked as deprecated and made optional in the build system.

@dmethvin
Copy link

dmethvin commented Mar 1, 2014

@cowboy, it's not just about changing old code, because I agree that the majority of old code should be left alone and in reality it is left alone.

It's about changing years of old blogs, StackOverflow advice, and documentation scattered around the net. That's why a new API is the only way to be sure that all the Google searches don't turn up a frustrating amount of incorrect information.

@dmethvin
Copy link

dmethvin commented Mar 1, 2014

Also remember we are part of an ecosystem that includes a huge number of third-party plugins. If we break some popular plugin by changing an existing API, we break the pages of people who try to write new code with that plugin and the new jQuery version. There's only so far we can go with a plugin like jQuery Migrate before it gets out of hand. Again, a new API gives us flexibility.

@cowboy
Copy link
Author

cowboy commented Mar 1, 2014

@dmethvin, I know that part of what makes jQuery maintainers good at, well, maintaining jQuery is the mindset where, when a bug or weird behavior is encountered in a browser, you fix it. But you're talking about the way the internet works; there will always be outdated or incorrect blogs, StackOverflow advice and documentation scattered around the net. It's not your job as the maintainers of a small software library to fix the way people use the internet; it's your job to make a library with an awesome API. Fortunately, just like with every other software library they use, developers will figure out how to use it. I mean, jQuery has fantastic official documentation.

I understand about the plugin thing, I happen to maintain a tool that has thousands of plugins. Updating the tool sometimes breaks plugins, which people don't like. But fortunately, users can continue to use the old version of the tool until the plugin they want to use gets updated. People aren't forced to upgrade!

@dmethvin
Copy link

dmethvin commented Mar 1, 2014

Okay, so you're proposing a drastic breaking change to the existing API. Write some code that defines the way you want it to work. Explain why we should make that breaking change rather than creating a new API that uses the emerging Promise standard.

@cowboy
Copy link
Author

cowboy commented Mar 1, 2014

A new API that uses the emerging Promise standard sounds fantastic!

Also, I think that setting users' expectations in the ways I've suggested sounds fantastic, too.

Win/win!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment