在循环中链接嵌套的承诺

Chaining nested promises in the loop

有一个控制器使用 $http.get() 从服务器获取数据的服务获取国家和城市。国家和城市都是json数组。

当前实施

服务

service.getCountries = function() {
    return $http.get('url');
}

service.getCities = function(country) {
    return $http.get('url' + country);
}

控制器

        var getCountries = function () {
            service.getCountries()
                .success(function (countries) {
                    angular.forEach(countries, function (country) {
                        // process country
                        getCities(country);
                    });
                })
                .error(function () {
                    alert('failed to load countries');
                });
        };

        var getCities = function (country) {
            service.getCities(country)
                .success(function (cities) {
                    angular.forEach(cities, function (city) {
                        // process city
                    });
                })
                .error(function () {
                    alert('failed to load cities of ' + country);
                });
        };

        var doAfterCountriesAndCitiesLoaded = function () {
            // do
        }

        getCountries();
        doAfterCountriesAndCitiesLoaded();

我想链接国家和城市的提取,以便 doAfterCountriesAndCitiesLoaded() 作为最后一个链进行处理。
如何通过适当的错误处理将此代码转换为 promise 链接?

Return service.getCountries 调用的结果(这是一个承诺)并将结果与​​ thencatch 链接起来。在前者的回调函数调用 doAfterCountriesAndCitiesLoaded 和后者的处理任何错误中。

var getCountries = function () {
   return service.getCountries()
      .then(function (countries) {
        ....
};

getCountries()
   .then(function(countries){
       doAfterCountriesAndCitiesLoaded(countries);
   }
   .catch(error){
       //handle errors
   }

当您需要并行执行多个 promise 时,您需要 $q.all,并且为了链接操作,您需要 return 您的 promise:

var getCountries = function () {
     return service.getCountries()
         .then(function (result) {
             return $q.all(result.data.map(getCities));
         }).catch(function (result) {
             var message = 'failed to load countries';
             console.log(message);
             throw new Error(message);
         });
};

var getCities = function (country) {
     return service.getCities(country)
         .then(function (result) {
             angular.forEach(result.data, function (city) {
                 // process city
             });
         }).catch(function () {
             var message = 'failed to load cities of ' + country;
             console.log(message);
             throw new Error(message);
         });    
};

var doAfterCountriesAndCitiesLoaded = function () {
      // do
};

getCountries().then(doAfterCountriesAndCitiesLoaded);