【问题标题】:linking promises, or one promise triggers another链接承诺,或一个承诺触发另一个
【发布时间】:2013-11-25 04:02:30
【问题描述】:

我正在构建一个天气应用程序,我首先必须获取用户的位置,然后发出获取天气的请求。

所以我有一个GeolocationService 和一个WeatherService。我的WeatherService 目前正在调用Geolocation 服务。如何让WeatherService 等到它有来自GeolocationService 的结果后再发出HTTP 请求?

app.factory('GeolocationService',function($q,$window,$rootScope){ 返回 { getLatLon:函数(){ var deferred = $q.defer(); 如果(!window.navigator){ $rootScope.$apply(function(){ deferred.reject(new Error("地理位置不可用")); }); } 别的 { $window.navigator.geolocation.getCurrentPosition(函数(位置){ $rootScope.$apply(function(){ deferred.resolve(位置); }); },函数(错误){ $rootScope.$apply(function(){ deferred.reject(错误); }); }); } 返回 deferred.promise; } }; }); app.factory("WeatherService", function ($q,$http,$rootScope, GeolocationService) { 返回 { 获取天气:函数(){ var 天气; var loc = new GeolocationService.getLatLon(); var lat= loc.lat || 37.4568202221774, lon= loc.lon || -122.201366838789; 变量单位 = ''; var url = 'http://api.openweathermap.org/data/2.5/forecast/daily?lat='+lat+'&lon='+lon+'&units='+units+'&callback=JSON_CALLBACK'; $http.jsonp(网址) .成功(功能(数据){ 天气=数据; 返回天气; }) .错误(函数(错误){ 天气=错误; 返回错误; }); } }; });

【问题讨论】:

  • 真的不认为你需要在$apply 中包含resolve 和reject,不知道是什么想法
  • @charlietfl - 我试过不将解析包装在 $apply 中,但没有它就不会触发 .then。

标签: javascript angularjs promise


【解决方案1】:

你只需要在你的服务中使用承诺,然后链接承诺。对于示例,我有一个 user.company_id 的用户,如果我想获得公司的名称,我必须等待用户加载。和你的情况一样。

这是我的服务:

    angular.module('UserService', []) 
.factory('UserService', function($q , $http, $rootScope,$timeout) {
var currentUserPromise = null;
var currentCompanyPromise = null;
return {
    getCurrentUser: function() {
        if (currentUserPromise === null) {
            var config = {};
            config.cache = true;
            config.method = "GET"; 
            config.url = "users/get_current_user";
            currentUserPromise = $http(config)
                .then(function(response) {
                    if (typeof response.data === 'object') {
                        return response.data.user;
                    } else {
                        // invalid response
                        return $q.reject(response.data);
                    }  
                }, function(response) {
                    // something went wrong
                    return $q.reject(response.data);
                });
        }
        return currentUserPromise;
    },

    getCurrentCompany: function(company_id) {
        if (currentCompanyPromise === null){
            var config = {};
            var company = {};
            company.id = company_id; 
            config.cache = true;
            config.method = "GET"; 
            config.url = "/companies/show";
            config.params = company;
            currentCompanyPromise = $http(config)
                .then(function(response) {
                    if (typeof response.data === 'object') {
                        return response.data.company;
                    } else {
                        // invalid response
                        return $q.reject(response.data);
                    }

                }, function(response) {
                    // something went wrong
                    return $q.reject(response.data);
                });
            }
            return currentCompanyPromise;

        }
    };     
});

在我的控制器中,我这样使用:

控制器:

var promiseCurrentUser = UserService.getCurrentUser();
promiseCurrentUser.then(function(user) {
    $scope.currentUser = user;
    UserService.getCurrentCompany(user.company_id).then(function(company){
        $scope.companyName = company.name;
    });
});

promise 最酷的地方在于它是一次性解决的。

希望对你有帮助。

【讨论】:

    【解决方案2】:

    您的GeolocationService 的函数getLatLon 正在返回一个承诺。无需使用new 运算符调用它。

    您的getWeather 函数应该类似于:

    app.factory("WeatherService", function ($q,$http,$rootScope, GeolocationService) {
        return {
            getWeather: function(){
                var weather;
                return GeolocationService.getLatLon().then(
                    function (loc) {
                        var  lat= loc.lat || 37.4568202221774, 
                        lon= loc.lon || -122.201366838789 ;
                        var units = '';
                        var url = 'http://api.openweathermap.org/data/2.5/forecast/daily?lat='+lat+'&lon='+lon+'&units='+units+'&callback=JSON_CALLBACK';
                        return $http.jsonp(url)
                            .success(function(data) {
                                weather=data;
                                return weather;
                            })
                            .error(function(err){
                                weather=err;
                                return err;
                            });
                });
            }
        }
    }
    

    在这里,我们首先调用GeolocationService.getLatLon() 来获得承诺。然后我们将我们的处理链作为一个链链接到它。成功函数会得到position,你在这里解决它deferred.resolve(position);

    此外,您不需要将resolvereject 包装在$apply 中。因此,您的GeoLocationService 可以简化为:

                if(!window.navigator){
                    deferred.reject(new Error("Geolocation not available"));
                } else {
                    $window.navigator.geolocation.getCurrentPosition(function(position){
                            deferred.resolve(position);
                    }, function(error){
                            deferred.reject(error);
                    });
                }
    

    【讨论】:

    • 感谢@musically_ut,如果不包装延迟,.then 不会被触发。此外,从成功语句返回 weather 不会将 weather 传递给范围。我的范围只是$scope.weather = WeatherModel.getWeather();
    • 您使用的是哪个版本的 Angular?最新版本 (1.2) makes promises A+ compliant,它们应该在不需要额外的 $digest 循环的情况下触发。 weather 传递给范围,但作为一个承诺。如果您的任何操作依赖于weather 的值,请将它们包含在一个链中:$scope.weather.then(function (weatherData) { ... })。或者在 then: WeatherModel.getWeather().then(function (weatherData) { $scope.weather = weatherData; }) 中分配 weather。不过,这两者都是异步
    • 这就解释了,我正在使用 v 1.5,希望在即将发布的版本中升级。我尝试了链接“then”的建议,但收到错误“无法调用未定义匿名函数的方法”。
    • 刚刚又测试了一遍,我的电话里肯定有()
    猜你喜欢
    • 2016-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-18
    • 1970-01-01
    相关资源
    最近更新 更多