Как преобразовать массив объектов обещания в объект обещания массива?

Есть ли способ преобразовать массив объектов обещания в объект обещания массива? Я ищу что-то вроде $q.all(promises) в AngularJS.

Вот мой код:

var getPages = function(courses) {
  var courses_promises = courses.filter(function(item) {
    return item.courses[0].home_link;
  }).map(function(item) {
    deferred = $.Deferred();
    item["class_link"] = item.courses[0].home_link;
    item["home_link"] = item["class_link"] + "class/index";
    $.get(item.home_link)
       .then(function(response) {
        item["html"] = response;
        deferred.resolve(item);
       });
    return deferred.promise();
  });
  return $.when.apply($, courses_promises);
};  

Я хочу, чтобы функция getPages возвращала одно обещание, которое будет разрешено с массивом значений, каждое значение соответствует обещанию с тем же индексом в массиве обещаний. Если какое-либо из обещаний разрешается с отклонением, это результирующее обещание будет разрешено с таким же отклонением.

И тогда я бы использовал

getPages.then(getEvents)

где getEvents — еще одна функция, которая ожидает массив с элементами, разрешенными getPages.

Может кто-нибудь мне помочь? Благодарю вас!


person plrthink    schedule 25.04.2013    source источник


Ответы (3)


Если вы используете Q, просто выполните:

Q.all(promises)

Как правило, это гораздо лучшая идея, чем использование jQuery для ваших обещаний, поскольку Q имеет гораздо лучший дизайн. Кроме того, можно безопасно давать Q.all обещания jQuery, и он прекрасно их усвоит.

Если вы не хотите использовать Q, я считаю, что $.when делает что-то подобное, но это не так просто и понятно.

person ForbesLindesay    schedule 25.04.2013
comment
Спасибо. Но как использовать q в моем файле js? - person plrthink; 25.04.2013
comment
Самый простой вариант — скачать q с raw.github.com/kriskowal/ q/master/q.min.js, а затем добавьте ссылку на него с помощью тега скрипта (<script src="q.min.js"></script>) - person ForbesLindesay; 25.04.2013
comment
Тем не менее, если вы создаете что-то достаточно сложное, я бы рекомендовал использовать browserify.org для всей вашей разработки, а затем он работает так же, как node.js на стороне сервера, и вы можете сделать: npm install q для установки и var Q = require('q') для использования - person ForbesLindesay; 25.04.2013
comment
Спасибо. Но я просто пишу простой скрипт, и я хочу использовать jquery для решения этой проблемы. И я новичок в веб-разработке, спасибо, что представили мне возможности для библиотеки. Благодарю вас! - person plrthink; 26.04.2013

Для тех, кто не хочет использовать другую библиотеку (хотя я могу подтвердить, что Q великолепен, кажется, это лучшая система обещаний для узла), вот реализация Q.all с использованием jQuery when:

function all(arrayOfPromises) {
    return jQuery.when.apply(jQuery, arrayOfPromises).then(function() {
        return Array.prototype.slice.call(arguments, 0);
    });
};

Это должно заботиться о двух проблемах:

  1. Вместо того, чтобы принимать массив, jQuery.when принимает переменное количество аргументов, поэтому мы должны вызывать его с apply, чтобы передать ему наш массив обещаний.
  2. Комбинированное обещание разрешается с несколькими аргументами вместо одного аргумента массива, поэтому нам нужно превратить arguments в реальный массив (используя slice).

Следовательно:

var getAnimal = function(animal) {
    return $.get('animals/' + animal);
};

var arrayOfPromisesToAnimals = ['frog', 'cat', 'horse'].map(getAnimal);

var promiseToArrayOfAnimals = all(arrayOfPromisesToAnimals);

promiseToArrayOfAnimals.then(function(arrayOfAnimals) {

    arrayOfAnimals.forEach(function(animal) {
        console.log(animal);
    });
});
person Daniel Earwicker    schedule 13.09.2013

Где promises — это массив, jQuery-эквивалент Q.all(promises):

jQuery.when.apply(null, promises);

который используют многие программисты jQuery, соглашаясь с тем, что это неуклюже. Для jQuery.when() было бы лучше принять массив.

РЕДАКТИРОВАТЬ

Теперь я видел полную функцию getPages, я могу лучше посоветовать решение jQuery:

Я думаю, что это так просто:

var getPages = function(courses) {
    var promises = courses.map(function(c) {
        if(!c.courses[0].home_link) return null;//filter action
        return $.get(c.courses[0].home_link + "class/index").done(function(response) {
            c.html = response;
        });
    }).get();//Remove jQuery wrapper to reveal an array of jqXHR promises.
    return $.when.apply($, promises);
};

Строка $.when.apply($, promises) всегда была правильной. Вам просто нужно убедиться, что promises является подлинным массивом javascript, а не коллекцией jQuery.

person Beetroot-Beetroot    schedule 25.04.2013
comment
Спасибо, но это не работает для меня. У меня есть массив обещаний, и каждое обещание разрешается со значением, которое будет передано методу then. Когда я попробую $.when.apply($, promises).then(function(promises){console.log(promises)}), он выведет на консоль значение первого обещания. Я хочу, чтобы результатом был обещанный массив, и каждый элемент в этом массиве является значением, которое разрешено для каждого обещания. - person plrthink; 26.04.2013
comment
Вот почему jQuery отстой для такого рода вещей, если вы сделаете console.log(arguments), вы получите то, что хотите, я думаю, потому что jQuery распределяет результаты среди аргументов функции, к которой вы затем переходите. - person ForbesLindesay; 26.04.2013
comment
jQuery.when.apply(null, promises) и $.when.apply($, promises) должны вести себя одинаково. $ === jQuery, а первый параметр, передаваемый в apply(), в этом случае произвольный. - person Beetroot-Beetroot; 26.04.2013
comment
Но на самом деле я хочу вернуть весь массив, а не только обещание. - person plrthink; 26.04.2013
comment
Тогда просто используйте Q как зависимость, это сделает жизнь намного проще. - person ForbesLindesay; 26.04.2013
comment
В этом случае вы сейчас спрашиваете о чем-то отличном от вопроса. - person Beetroot-Beetroot; 26.04.2013
comment
Да, наконец-то я использовал Q для решения проблемы. Спасибо, вы классные! - person plrthink; 27.04.2013
comment
Потрясающие! Я изменился таким образом, Спасибо! - person plrthink; 29.04.2013