AngularJS: espere a que se completen varias consultas de recursos


105

Tengo una sola fábrica definida con ngResource:

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

Estoy haciendo varias llamadas al método de consulta definido en esta fábrica. Las llamadas pueden ocurrir de forma asincrónica, pero necesito esperar a que se completen ambas llamadas antes de continuar:

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

¿Hay alguna manera de hacer esto con las fábricas de AngularJS definidas con ngResource, similar a la funcionalidad $ .when (). Then () de jQuery? Preferiría no agregar jQuery a mi proyecto actual.

Respuestas:


200

Querrá usar promesas y $ q.all () .

Básicamente, puede usarlo para envolver todas sus llamadas $ resource o $ http porque devuelven promesas.

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
Los recursos no devuelven promesas, devuelven objetos para completar en el futuro. Sin embargo, en la versión 1.1.3 inestable , los recursos también tienen $thenpropiedad pero no exponen ningún objeto de promesa. Exponer por $promisecompleto estaría en 1.1.4
Umur Kontacı

@ UmurKontacı ¡Desafortunadamente esto no está en angular 1.1.4!
NH2

Los detalles sobre el problema de los recursos no son promesas se pueden encontrar en este hilo y en esta solicitud de extracción .
nh2

1
Esta respuesta muestra cómo escribirlo una vez que se implementa.
nh2

3
Su respuesta es muy útil y creo que es la forma más sensata de convertir recursos en promesas en el angular actual. Podría ser útil agregar que en la documentación de $q, a la que se vinculó, garantiza que la matriz de resultados está en el mismo orden que la matriz de promesa.
nh2

20

Creo que una mejor solución es:

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

1
Para mí funcionó sin $ promise al final ... Al igual que: Account.query ({type: 'billing'}), Account.query ({type: 'shipping'})
georgeos

12

La solución de Ben Lesh es la mejor pero no está completa. Si necesita manejar condiciones de error, y sí, lo hace, entonces debe usar el catchmétodo en la API de promesa de esta manera:

$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...

});

Si no define catchy todas sus promesas fallan, el thenmétodo nunca se ejecutará y, por lo tanto, probablemente dejará su interfaz en mal estado.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.