AngularJS回调流程

时间:2014-09-04 01:31:37

标签: angularjs cordova ionic-framework

我们正在使用AngularJS和Ionic框架创建基于PhoneGap的应用程序。

此应用程序是一个商店管理系统,它使用OAuth2与现有的Web应用程序绑定。

该应用包含一个'订单'显示客户已收到的订单列表的视图。在加载订单列表之前,以下函数验证用户的访问令牌是否仍然有效,如果没有,则获得新的。

function verifyAccessToken() {


            var now = new Date().getTime();

            if (now > tokenStore.access_token_expiry_date) {

                // renew access token
                $http({
                    url: '*API URL*/token',
                    method: "POST",
                    data: { 
                        refresh_token : tokenStore.refresh_token,
                        grant_type : 'refresh_token',
                        client_id: clientId,
                        client_secret: clientSecret,
                        redirect_uri: redirectURI 
                    },
                    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                    transformRequest: function(obj) {
                        var str = [];
                        for(var p in obj)
                        str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
                        return str.join("&");
                    }                       
                })
                .success(function (data, status, headers, config) {
                    tokenStore['access_token'] = data.access_token;
                    var expiresAt = now + parseInt(data.expires_in, 10) * 1000 - 10000;
                    tokenStore['access_token_expiry_date'] = expiresAt;
                    console.log(data.access_token);
                })
                .error(function (data, status, headers, config) {
                    if(status=='404') {
                        $rootScope.$emit('serviceUnavailable');
                    }
                    if(status=='400' || status=='401') {
                        $rootScope.$emit('tokenUnauthorized');
                    }
                    console.log(status);
                    console.log(data);          
                }); 
            } 


        };

然后使用新的访问令牌

调用订单列表
return $http({method: 'GET', url: '*API URL*?access_token=' + tokenStore.access_token, params: {}})
                .error(function(data, status, headers, config) {
                    if(status=='404') {
                        $rootScope.$emit('serviceUnavailable');
                    }
                    if(status=='401') {
                        $rootScope.$emit('tokenUnauthorized');
                    }
                    console.log(status);
                    console.log(data);  
                });     
        }

问题是HTTP GET没有等待VerifyAccessToken函数完成。

如何构建以避免此问题?

您可以提供任何建议。

更新2 (在克莱德回答之后):

我更新了 oauth-angular.js 中的两个函数,如下所述:

verifyAccessToken 函数现在显示如下:

    function verifyAccessToken() {
        var deferred = $q.defer();

        if ( (new Date().getTime()) < tokenStore.access_token_expiry_date ) {
            /* token is still valid, resolve the deferred and bail early */
            deferred.resolve();
            return deferred.promise;
        }

        /* token is not valid, renew it */
        alert('getting new access token')
        $http({
            url: 'https://' + tokenStore.site_name + '.somedomain.com/api/oauth2/token',
            method: "POST",
            data: { 
                refresh_token : tokenStore.refresh_token,
                grant_type : 'refresh_token',
                client_id: clientId,
                client_secret: clientSecret,
                redirect_uri: redirectURI 
            },
            headers: {'Content-Type': 'application/x-www-form-urlencoded'},
            transformRequest: function(obj) {
                var str = [];
                for(var p in obj)
                str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
                return str.join("&");
            }                       
        }).success(function (data, status, headers, config) {
            tokenStore['access_token'] = data.access_token;
            var now = new Date().getTime();
            var expiresAt = now + parseInt(data.expires_in, 10) * 1000 - 10000;
            tokenStore['access_token_expiry_date'] = expiresAt;
            console.log(data.access_token);
            deferred.resolve();
        })
        .error(function (data, status, headers, config) {
            if(status=='404') {
                $rootScope.$emit('serviceUnavailable');
            }
            if(status=='400' || status=='401') {
                $rootScope.$emit('tokenUnauthorized');
            }
            console.log(status);
            console.log(data);
            deferred.reject(); // as the last step, reject the deferred, there was a failure
        });

        return deferred.promise;
    }

,getOrders函数现在如下所示:

function getOrders() {

         verifyAccessToken().then(
            function() {
                return $http({method: 'GET', url: 'https://' + tokenStore.site_name + '.somedomain.com/api/1.0/orders?access_token=' + tokenStore.access_token, params: {}})
                    .error(function(data, status, headers, config) {
                        if(status=='404') {
                            $rootScope.$emit('serviceUnavailable');
                        }
                        if(status=='401') {
                            $rootScope.$emit('tokenUnauthorized');
                        }
                        console.log(status);
                        console.log(data);  
                    });
            },
            function() {
                /* code to handle a failure of renewing the token */
            });

    }

我的 controllers.js 文件现在在执行函数getOrders时抛出以下错误。

TypeError:无法读取属性&#39;成功&#39;未定义的

.controller('OrdersCtrl', function ($scope, $stateParams, oauth, $ionicLoading) {

        function loadOrders() {

        $scope.show();

        oauth.getOrders()
            .success(function (result) {
                $scope.hide();
                $scope.orders = result;
                console.log(result);
                // Used with pull-to-refresh
                $scope.$broadcast('scroll.refreshComplete');
            })
            .error(function(data) {
                $scope.hide();
            });
    }
})

之前没有任何问题。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

$http的返回值为promise。每当函数返回一个promise时,它最有可能执行异步操作。这意味着函数调用将立即返回一个对象,然后您可以在该操作完成时调用其他方法。

在这种情况下,您应该重新安排verifyAccessToken函数以返回自己的承诺。

类似的东西:

function verifyAccessToken() {
    var deferred = $q.defer();

    if ( (new Date().getTime()) < tokenStore.access_token_expiry_date ) {
        /* token is still valid, resolve the deferred and bail early */
        deferred.resolve();
        return deferred.promise;
    }

    /* token is not valid, renew it */
    $http({
        /* stuff */
    }).success(function() {
        /* stuff */
        deferred.resolve(); // resolve the deferred as the last step
    })
    .error(function() {
        /* stuff */
        deferred.reject(); // as the last step, reject the deferred, there was a failure
    });

    return deferred.promise;
}

然后当你去调用verifyAccessToken时,你会做类似的事情:

/* stuff before the verifyAccessToken call */
verifyAccessToken().then(
    function() {
        /* any stuff after the verifyAccessToken call */
        /* or any code that was dependent on verifying the access token */
    },
    function() {
        /* code to handle a failure of renewing the token */
    });
/*
     there should be nothing after the call that depends on verifying the
     access token. Remember this asynchronous so the initial call to verifyAccessToken
     is going to return immediately. Then sometime in the future the success
     or error call back will be called.
*/