将jQuery Promise数组转换为jQuery Promise数组的最简洁方法是什么?

15

我遇到了这样的情况:我有一个包含多个JQuery Promise的数组。

var arrayOfPromises = [ $.Deferred(), $.Deferred(), $.Deferred(), $.Deferred() ]

我需要将其转换为一个数组的 JQuery Promise

var promiseOfArray = someTransform(arrayOfPromises)

查询条件

promiseOfArray.done(function(anArray){
  alert(anArray.join(","));
});

创建一个带文本的提示框

result1,result2,result3,result4

我目前在 CoffeeScript 中定义了 someTransform,如下所示:

someTransform = (arrayOfPromises) ->
  $.when(arrayOfPromises...).pipe (promises...) ->
    promises

这将转换为以下JavaScript代码

var someTransform,
  __slice = [].slice;

someTransform = function(arrayOfPromises) {
  return $.when.apply($, arrayOfPromises).pipe(function() {
    var promises;
    promises = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
    return promises;
  });
};

这是一个 jsFiddle,展示了我正在寻找的结果。

我想知道是否有更好(更短、更简洁)的方法来定义 someTransform,以达到相同的结果?


可能是将一个Deferreds数组传递给$.when()的重复问题。 - Bergi
2个回答

35
你可以将数组作为参数应用到$.when中,只需使用apply即可。
var promiseOfArray = $.when.apply($, arrayOfPromises);
为了更清楚地使用这个,我喜欢向$添加一个方法:
$.whenall = function(arr) { return $.when.apply($, arr); };

现在你可以这样做:

$.whenall([deferred1, deferred2, ...]).done(...);

更新:默认情况下,done处理程序将每个结果作为单独的参数传递;您不会得到一个结果数组。

由于需要处理任意数量的Deferred对象,因此可以使用特殊的隐式arguments对象循环处理结果。

$.whenall([d1, d2, ...]).done(function() {
    for (var i = 0; i < arguments.length; i++) {
        // do something with arguments[i]
    }
});

如果你只是想将所有Deferred的字符串结果连接起来,我们可以使用一个小技巧。 arguments 类似于数组,但不是一个Array

$.whenall([d1, d2, ...]).done(function() {
    alert(Array.prototype.join.call(arguments, ','));
});
如果你想将一个结果数组返回给你的done回调函数,我们可以调整whenall使它实现
$.whenall = function(arr) {
    return $.when.apply($, arr).pipe(function() {
        return Array.prototype.slice.call(arguments);
    });
};

我认为OP实际上是在寻求一种“更短,更干净”的方法,并且已经知道了.apply()的存在。 - jAndy
我会让问题更清晰,但我相信这将使用result1,result2,...调用完成,但我希望它使用单个参数[result1,result2,...]调用完成。请参见http://jsfiddle.net/qk2mT/2/,“抛出对象0没有方法'join'” - Bobby
1
@Soldier.moth:done 处理程序不会得到一个结果数组;相反,它会传递 n 个参数,其中 n 是您最初传递的 Deferreds 的数量。使用隐式的 arguments 对象循环遍历结果。 - josh3736
@josh3736:是的,我希望有一种好的方法可以将arguments转换为数组。可能可以通过定义类似于$.whenall的函数来实现,例如:function(arr) { return $.when.apply($,arr).pipe(function(){ return [].slice.call(arguments,0); }); } - Bobby
@Soldier.moth:没错,就是这样。我会使用Array.prototype.slice而不是[],这样你就不必创建一个不必要的数组实例了。请看更新。 - josh3736

6

每次我们需要在多个promises上调用"丑陋"的行 $.when.apply 都让我很烦恼。但是,Function.prototype.bind 解决了这个问题!

var when = Function.prototype.apply.bind( jQuery.when, null );

现在,我们只需调用
when( someArrayWithPromises ).done(function() {
});

Function.prototype.bind 是 ES5 的一部分,并且在各种浏览器中广泛使用。如果您需要支持非常老的浏览器,那么有很多简单的 shims 可供使用。


你必须小心使用 bind,因为它在旧浏览器中不可用。 - josh3736

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接