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

У меня есть один factory, определенный с помощью ngResource:

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

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

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 в мой текущий проект.

Ответ 1

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

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

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

Ответ 2

Я думаю, что лучшее решение:

$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...
});

Ответ 3

Решение от Ben Lesh является лучшим, но оно не завершено. Если вам нужно обрабатывать условия ошибки - и, да, вы делаете - тогда вы должны использовать метод 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 и все ваши ошибки promises не выполняются, метод then никогда не будет выполняться и, следовательно, вероятно, ваш интерфейс окажется в плохом состоянии.