如何在 app.run 中使用异步代码

How use async code inside app.run?

本文关键字:异步 代码 run app      更新时间:2023-09-26

我有一个运行块正在查询我的服务器以检查用户是否经过身份验证。

.run(function($http, userService){
    var base_url = 'http://server.com:3000';
    $http.get(base_url + '/users/isloggedin')
        .success(function(data, status, headers, config){
            userService.setUserData(data.userData);
            userService.setIsUserLoggedIn(true);
        });
})

稍后,我有另一个运行,需要来自第一个运行块的信息。这样做的问题是我的运行代码具有异步代码,并且我在第一次没有将真正的值获取到userService.getIsUserLoggedIn()。

如何告诉 angularjs 仅在第一个运行块完成后执行第二个运行块?

第二个运行块:

.run(function($rootScope, $location, $state, userService){
    //Run to handle authentication
    var authOnly = ['/painel'];
    var unAuthOnly = ['/home'];
    var checkAuthRoute = function(url){
        var exist = authOnly.indexOf(url);
        return exist > -1;
    };
    var checkUnAuthRoute = function(url){
        var exist = unAuthOnly.indexOf(url);
        return exist > -1;
    };
    $rootScope.$on('$stateChangeStart', function(evt, toState, toParams, fromState, fromParams){
        console.log(toState.url + ' ' + fromState.url + ' - ' + userService.getIsUserLoggedIn());
        if(!userService.getIsUserLoggedIn() && checkAuthRoute(toState.url)){
            console.log('Aqui..');
            evt.preventDefault();
            $state.go('login');
        }
    });
})

谢谢

你可以在 Javascript 中使用回调来发出链异步请求。像这样的东西可能会起作用:

.run(function($http, $rootScope, $location, $state, userService){
    var base_url = 'http://server.com:3000';
    $http.get(base_url + '/users/isloggedin')
        .success(function(data, status, headers, config){
            userService.setUserData(data.userData);
            userService.setIsUserLoggedIn(true);
            handleAuth($rootScope, $location, $state, userService);
        });
})

并在上面的.run代码之前定义此函数:

function handleAuth($rootScope, $location, $state, userService){
    var authOnly = ['/painel'];
    var unAuthOnly = ['/home'];
    var checkAuthRoute = function(url){
        var exist = authOnly.indexOf(url);
        return exist > -1;
    };
    var checkUnAuthRoute = function(url){
        var exist = unAuthOnly.indexOf(url);
        return exist > -1;
    };
    $rootScope.$on('$stateChangeStart', function(evt, toState, toParams, fromState, fromParams){
        console.log(toState.url + ' ' + fromState.url + ' - ' + userService.getIsUserLoggedIn());
        if(!userService.getIsUserLoggedIn() && checkAuthRoute(toState.url)){
            console.log('Aqui..');
            evt.preventDefault();
            $state.go('login');
        }
    });
}

或者一个更流行的替代方案(防止不断链接回调,使代码不可读 - 又名末日金字塔),是使用 Promises。

承诺

采用异步函数并返回一个承诺,您可以使用该承诺来链接请求(例如,$http 方法返回您正在使用的名为 success 的承诺)。它在 ECMAScript 5 中不可用,但在 6 中可用。人们已经做了一堆Promises的实现,比如Kris Kowal的Q,而Angular有一个名为$q的这个库的精简版本。

因为这是异步调用,所以从技术上讲,第一个块已经完成,但它里面的调用没有完成。我唯一想到的是将承诺添加到用户服务中并通过它进行通信:

.run(function($http, $q, userService){
    var base_url = 'http://server.com:3000';
    var deferred = q.defer();
    $http.get(base_url + '/users/isloggedin')
        .success(function(data, status, headers, config){
            userService.setUserData(data.userData);
            userService.setIsUserLoggedIn(true);
            deferred.resolve();
        });
    userService.setPromise(deferred.promise);
})

在第二轮中:

.run(function(userService){
        userService.getPromise().then(function(){
           //code that requires first run to finish
        });
    })
但是,如果在某个地方您需要从第二次运行

到完成的代码(我的意思是仅在第二次运行后才进行 smth),它将再次需要相同的结构,这并不好,因此您需要更改逻辑。