JQuery: $ .when behaves differently depending on the number of arguments

$, when it behaves differently depending on whether one or more deferred objects are passed to it. This behavior is documented in documents, but the problem is that it forces me to write two different code paths.

function foo (dfds) { $.when.apply(this, dfds).done(function() { console.log(arguments); }); } 

Case I:

 foo([$.getJSON("http://freegeoip.net/json/8.8.8.8"), $.getJSON("http://freegeoip.net/json/8.8.8.9")]); .... /* Output (what I'd come to expect) */ [Array[3], Array[3]] 

Case II:

 foo([$.getJSON("http://freegeoip.net/json/8.8.8.8")]); .... /* Output (the original unwrapped deferred arguments) */ [Object, "success", Object] 

Any way to elegantly handle this without resorting to checking the length of the dfd or type arguments ?

+6
source share
3 answers

I do not think that you can avoid explicitly testing the number of pending objects. Assuming you want to return a pending object:

 function foo (dfds) { if(dfds.length > 1) { return $.when.apply(this, dfds); } else { return dfds[0].pipe(function() { return [Array.prototype.slice.call(arguments, 0)] }); } } 

You can create a jQuery plugin to wrap this functionality and make it reusable:

 (function($) { $.when_ = function() { if(arguments.length > 1) { return $.when.apply(this, arguments); } else { return arguments[0].pipe(function() { return [Array.prototype.slice.call(arguments, 0)]; }); } }; }(jQuery)); 

You can also override $.when , but I don’t know for sure whether it is used internally or not.

+4
source

jQuery has a bad habit of ruining the logic of arguments. In your case, a simple loop will normalize it if you want a callback for each deferred object:

 $.each(dfds, function() { $.when(this).done(function() { console.log(arguments); }); }); 

You can also loop arguments, so you don't have to send an array:

 function foo() { $.each(arguments, function() { $.when(this).done(function() { console.log(arguments); }); }); } 

UPDATE

If you always want to return an array of a pending object, you probably need to check the length of the arguments in foo , as Felix posted, or do something like:

 function foo() { $.when.apply(this, arguments).done(function() { var args = $.makeArray(arguments), result = args[0].constructor != Array ? [args] : args; console.log(result); }); } 

http://jsfiddle.net/2ht8d/

+1
source

Just push the dummy object to the end of the dfds array. This ensures that it always has a length of 2 or more if you have at least one deferred.

0
source

Source: https://habr.com/ru/post/923354/


All Articles