AngularJS - дождитесь завершения нескольких запросов ресурсов

105

У меня есть одна фабрика, определенная с помощью ngResource:

App.factory('Account', function($resource) {
    return $resource('url', {}, {
        query: { method: 'GET' }
    });
});

Я выполняю несколько вызовов метода запроса, определенного на этой фабрике. Вызовы могут происходить асинхронно, но мне нужно дождаться завершения обоих вызовов, прежде чем продолжить:

App.controller('AccountsCtrl', function ($scope, Account) {
    $scope.loadAccounts = function () {
        var billingAccounts = Account.query({ type: 'billing' });
        var shippingAccounts = Account.query({ type: 'shipping' });

        // wait for both calls to complete before returning
    };
});

Есть ли способ сделать это с помощью фабрик AngularJS, определенных с помощью ngResource, аналогично функциональности jQuery $ .when (). Then ()? Я бы предпочел не добавлять jQuery в мой текущий проект.

Натан Донце
источник

Ответы:

201

Вы захотите использовать обещания и $ q.all () .

По сути, вы можете использовать его для обертывания всех ваших вызовов $ resource или $ http, потому что они возвращают обещания.

function doQuery(type) {
   var d = $q.defer();
   var result = Account.query({ type: type }, function() {
        d.resolve(result);
   });
   return d.promise;
}

$q.all([
   doQuery('billing'),
   doQuery('shipping')
]).then(function(data) {
   var billingAccounts = data[0];
   var shippingAccounts = data[1];

   //TODO: something...
});
Бен Леш
источник
17
Ресурсы не возвращают обещания, они возвращают объекты, которые нужно заполнить в будущем. Однако в нестабильной версии 1.1.3 ресурсы также имеют $thenсвойство, но не предоставляют никаких объектов обещаний. Разоблачение $promiseполностью будет в 1.1.4
Умур Kontacı
@ UmurKontacı Этого, к сожалению, нет в angular 1.1.4!
nh2
Подробности о ресурсах не обещают, проблему можно найти в этом потоке и в этом запросе на перенос .
nh2
1
Этот ответ показывает, как его написать после того, как он будет реализован.
nh2
3
Ваш ответ очень полезен, и я считаю, что это наиболее разумный способ конвертировать ресурсы в обещания в текущем angular. Было бы полезно добавить, что в документации $q, на которую вы ссылаетесь, это гарантирует, что массив результатов находится в том же порядке, что и массив обещаний.
nh2 04
20

Думаю, лучшее решение:

$q.all([
   Account.query({ type: 'billing' }).$promise,
   Account.query({ type: 'shipping' }).$promise
]).then(function(data) {
   var billingAccounts = data[0];
   var shippingAccounts = data[1];

   //TODO: something...
});
Tales Mundim Andrade Porto
источник
1
У меня сработало без обещания $ в конце ... Также как: Account.query ({type: 'billing'}), Account.query ({type: 'shipping'})
georgeos
12

Решение от Бена Леша - лучшее, но не полное. Если вам нужно обработать условия ошибки - и да, вы это делаете - тогда вы должны использовать catchметод в API обещаний следующим образом:

$q.all([
   doQuery('billing'),
   doQuery('shipping')
]).then(function(data) {
   var billingAccounts = data[0];
   var shippingAccounts = data[1];

   //TODO: something...

}).catch(function(data) {

   //TODO: handle the error conditions...

}).finally(function () {

  //TODO: do final clean up work, etc...

});

Если вы не определитесь catchи все ваши обещания не будут выполнены, то thenметод никогда не будет выполнен и, следовательно, вероятно, оставит ваш интерфейс в плохом состоянии.

Ник А. Уоттс
источник