Несколько promises из одного запроса $http в AngularJS

Я хотел бы реализовать promises в моем приложении AngularJS, как вы можете видеть в этом примере: qaru.site/info/16303/...

Мое приложение будет принимать несколько массивов данных, делающих несколько обращений к базе данных на моем сервере, но я настроил свой сервер, чтобы вернуть все эти данные в качестве одного ответа в идею минимизации запросов, чтобы мое приложение было как можно более эффективным ( данные по существу бесполезны, если только все данных не попадает на клиент). Поэтому вместо этого...

MyCtrl.resolve = {
    projects : function($q, $http) {
        return $http.get('/api/projects'});
    },
    clients : function($q, $http) {
        return $http.get('/api/clients'});
    }
};

Я хотел бы иметь возможность сделать одиночный $http запрос GET на URL, например /api/allData, а затем дать обещание для projects, которое будет установлено равным allData.projects и обещание для clients, которое будет установлено равным allData.clients и т.д. (где allData - это данные, которые возвратились с моим единственным запросом). Я все еще очень новичок в promises, может ли кто-нибудь дать мне пример того, как я настроил эти promises внутри MyCtrl.resolve?

Ответ 1

Ну, не так много смысла в использовании двух promises, которые, как вы знаете, представляют собой одно и то же обещание. Но вы действительно можете создать услугу, которая получит ручку, обещание и возвращение двух. Что-то вроде этого:

var mod = angular.module('mod', []);
mod.service('theService', function($q, $http) {
  return function() {
    var cliDeferred = $q.defer(),
        proDeferred = $q.defer();

    $http.doYourStuff().then(function _onSuccess(data) {
      cliDeferred.resolve(data.clients);
      proDeferred.resolve(data.projects);
    }, function _onError(err) {
      cliDeferred.reject(err);
      proDeferred.reject(err);
    });

    return {clients: cliDeffered.promise, projects: proDeferred.promise};
  };
});

Но, как я уже сказал, в этом нет особого смысла. Возможно, лучшее решение, учитывая, что ваша служба вернет массив, вернет объект с пустыми массивами и заполнит их при завершении обещания $http.

Ответ 2

Я считаю, что вы ищете:

var myApp = angular.module('myApp', []);

myApp.factory('myService', function ($http, $q) {
    return {
        getAllData: function () {
            return $q.all([ 
                // $q will keep the list of promises in a array
                $http.get('/api/projects'),
                $http.get('/api/clients')
            ]).then(function (results) {
            // once all the promises are completed .then() will be executed 
            // and results will have the object that contains the data 
                var aggregatedData = [];
                angular.forEach(results, function (result) {
                    aggregatedData = aggregatedData.concat(result.data);
                });
                 return aggregatedData;
            });
        }
     };
 });

Вы можете получить свои данные из окончательного массива aggregatedData (например: aggregatedData[0), aggregatedData [1],...)

Вы можете настроить эти promises внутри MyCtrl.resolve за один раз:

resolve = {
    getAllData : myService.getAllData()
}