我正在使用 event.preventDefault() 技术根据我从后端获取的标志值有条件地将用户重定向到适当的状态。一切似乎都工作正常,除了有时渲染实际页面然后发生重定向,而且在极少数情况下也是如此。实际页面的渲染持续时间也很短。以下是我正在使用的代码片段:
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
if (fromState.name === '' && toState.name === "myState"){
Auth.isLoggedInAsync(function(loggedIn) {
if (!loggedIn) {
event.preventDefault();
$state.go('state1');
} else {
event.preventDefault();
Auth.getNextStateForUser()
.then(function(data) {
console.log(data.nextState);
$state.go(data.nextState);
})
.catch(function(err){
console.log(err);
$state.go(toState.name);
});
}
});
我遵循的逻辑是,检查用户是否登录,然后重定向到 state1,否则根据从后端获取的 nextstateValue 重定向到下一个适当的状态。如果发生错误,则打开实际页面,不进行任何重定向。
我希望我能清楚地表达自己在做什么。只是想知道我面临的问题是否是真正的问题,或者我的做法有误。
我也将其发布在 github 页面上,但似乎我是唯一面临此问题的人。
请检查此以获取更多信息: https://github.com/angular-ui/ui-router/issues/2088
谢谢
编辑:根据答案,我更新了使用 ui-router 解析的代码,并将 isLoggedInAsyc 转换为返回 promise 。
resolve: {
promiseState: function(Auth, $state, $q, $stateParams) {
var deferred = $q.defer();
Auth.isLoggedInSync()
.then(function(isLoggedIn){
console.log(isLoggedIn);
if(isLoggedIn) {
Auth.getNextStateForUser()
.then(function(data) {
console.log(data.nextState);
$state.go(data.nextState);
deferred.resolve(data);
})
.catch(function(error) {
console.log(error);
deferred.reject(error);
});
}
deferred.resolve(isLoggedIn);
})
.catch(function(err){
console.log(err);
deferred.reject(err);
});
return deferred.promise;
}
}
我的 isLoggedIn() 返回 promise 。
isLoggedInSync: function(callback) {
var cb = callback || angular.noop;
var deferred = $q.defer();
if(currentUser.hasOwnProperty('$promise')) {
currentUser.$promise.then(function() {
deferred.resolve(true);
return cb(true);
}).catch(function() {
deferred.resolve(false);
return cb(false);
});
} else if(currentUser.hasOwnProperty('role')) {
deferred.resolve(true);
} else {
deferred.resolve(false);
}
return deferred.promise;
}
最佳答案
正如 @milaenlempera 提到的,所有 Angular 事件都是同步的,在这种情况下没有真正的方法可以很好地处理异步。我们的生产代码中遇到了这个问题,我们的解决方案是使用 ui-router 中的 resolve
功能。这就是我们解决它的方法(显然插入到您的代码中)
.state({
name: 'myState',
resolve: {
principal: ['Auth', '$state', '$q', function(Auth, $state, $q) {
var deferred = $q.defer();
Auth.isLoggedInAsync(function(loggedIn) {
if(!isLoggedIn) {
deferred.resolve($state.go('state1'));
return;
}
return Auth.getNextStateForUser()
.then(function(data) {
$state.go(data.nextState);
})
.catch(function(error) {
deferred.reject(error);
});
});
return deferred.promise;
}]
}
});
我建议使用 Auth.isLoggedInAsync
返回一个 promise 。
此外,如果 Auth.getNextStateForUser()
被拒绝,您的原始代码将导致无限循环。它将尝试转到名为 toState.name
的状态,这是刚刚导致错误的状态,这将导致另一个错误并导致它转到 toState.name
....
由于resolve
级联,如果您想共享权限规则,则可以实现子状态。确实很糟糕,没有办法只在状态上放置一个属性并在其他地方处理异步权限检查,但这就是我们目前遇到的情况。
根据评论,这是一个使用修改后的代码进行 promise 链接的示例。
promiseState: ['Auth', '$state', function(Auth, $state) {
return Auth.isLoggedInSync()
.then(function(isLoggedIn) {
if(isLoggedIn) {
return Auth.getNextStateForUser().then(function(data) {
return data.nextState;
});
}
// If the user isn't logged in, return the state that you should go to instead
return 'state1';
})
.then(function(nextState) {
return $state.go(nextState);
});
}]
关于javascript - event.preventDefault() 不等待 promise 解决,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31368338/