Каков самый чистый способ превратить массив JQuery Promises в JQuery Promise массива?
Я столкнулся с ситуацией, когда у меня несколько JQuery Promises в массиве
var arrayOfPromises = [ $.Deferred(), $.Deferred(), $.Deferred(), $.Deferred() ]
и нужно превратить его в JQuery Promise массива
var promiseOfArray = someTransform(arrayOfPromises)
где
promiseOfArray.done(function(anArray){
alert(anArray.join(","));
});
создает предупреждение с текстом
результат1, результат2, result3, result4
В настоящее время я определяю someTransform
в coffeescript как
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
для достижения того же результата?
Ответы
Ответ 1
Вы можете просто apply массив в качестве аргументов $.when
.
var promiseOfArray = $.when.apply($, arrayOfPromises);
Чтобы использовать это яснее, мне нравится добавлять метод к $
:
$.whenall = function(arr) { return $.when.apply($, arr); };
Теперь вы можете сделать:
$.whenall([deferred1, deferred2, ...]).done(...);
Обновление: По умолчанию обработчик done
получает каждый результат, передаваемый как отдельный аргумент; вы не получите массив результатов.
Поскольку вам нужно обрабатывать произвольное количество отложенных периодов, вы можете использовать специальный неявный объект arguments
для обработки результатов.
$.whenall([d1, d2, ...]).done(function() {
for (var i = 0; i < arguments.length; i++) {
// do something with arguments[i]
}
});
Если вы действительно хотите присоединиться к строковому результату всех ваших отсрочек, мы можем использовать небольшой хакерский хакер. 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);
});
};
Ответ 2
Это также беспокоило меня, что всегда нужно набирать "уродливую" строку $.when.apply
, когда нам нужно ее вызывать на нескольких promises. Но Function.prototype.bind
для спасения!
var when = Function.prototype.apply.bind( jQuery.when, null );
Теперь мы можем просто позвонить
when( someArrayWithPromises ).done(function() {
});
Function.prototype.bind
является частью ES5 и очень широко доступен в браузерах. Есть много удобных прокладок, если вам нужно поддерживать очень старые браузеры, а также