Jquery:$ .when根据参数的数量表现不同

$ .when的行为会有所不同,具体取决于是否将一个或多个Deferred对象传递给它。 这种行为记录在文档中 – 但问题是它迫使我编写两个不同的代码路径。

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

案例一:

 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]] 

案例二:

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

有没有办法优雅地处理这个而不需要检查dfd的长度或arguments的类型?

我认为你不能避免显式测试延迟对象的数量。 假设您要返回延迟对象:

 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)] }); } } 

您可以创建一个jQuery插件来包装此function并使其可重用:

 (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)); 

您也可以覆盖$.when但我不确定它是否在内部使用。

jQuery有一个乱搞参数逻辑的坏习惯。 在您的情况下,如果您想要为每个延迟对象进行回调,则一个简单的循环会对其进行规范化:

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

您还可以循环参数,这样您就不必发送数组:

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

UPDATE

如果你总是希望返回一个延迟对象数组,你可能需要像Felix发布的那样检查foo的参数长度,或者执行以下操作:

 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/

只需将虚拟对象推到dfds数组的末尾即可。 这将确保它始终具有2或更大的长度,假设您至少有一个延迟。