event.preventDefault()不等到promise被解决

时间:2015-07-12 13:36:02

标签: javascript angularjs express angular-ui-router

我正在使用event.preventDefault()技术根据我从后端获取的标志值有条件地将用户重定向到适当的状态。 Eveything似乎工作正常,除了有时实际页面被渲染,然后重定向发生,在极少数情况下也是如此。这个实际页面的渲染也持续很短的时间。以下是我正在使用的代码片段:

grep -v '^09:23\b' file

我遵循的逻辑是,检查用户是否已登录,然后重定向到state1,否则根据从后端获取的nextstateValue重定向到下一个适当的状态。如果发生某些错误,请打开实际页面而不进行任何重定向。

我希望我能清楚自己所做的事情。只是想知道我所面临的问题是否是真正的问题,或者我在做什么是错的。

我也在github页面上发布了它,但似乎我是唯一一个面临这个问题的人。

请查看此信息以获取更多信息: https://github.com/angular-ui/ui-router/issues/2088

由于

编辑:根据答案,我更新了使用ui-router解析的代码并转换了我的isLoggedInAsyc以返回promise。

$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);
          });
      }
    });

我的isLoggedIn()返回了诺言。

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;
  }
}

2 个答案:

答案 0 :(得分:1)

正如@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返回承诺。

此外,如果拒绝Auth.getNextStateForUser(),原始代码将导致无限循环。它将尝试转到名为toState.name的状态,这是导致错误的状态,这将导致另一个错误并导致它转到toState.name ....

由于resolve级联,如果要共享权限规则,则可以实现子状态。它真的很糟糕,没有办法只在属性上放置一个属性并在其他地方处理异步权限检查,但那是我们此刻处理的那一手。

根据评论,这是一个使用修改后的代码进行承诺链接的示例。

  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);
      });
  }]

答案 1 :(得分:0)

角度事件是同步的。 如果需要停止它,则必须在事件处理函数中同步执行。 在您的示例中,异步检查登录,同时路由继续。这就是你看到页面并在之后重定向的原因。

$rootScope.$on('$stateChangeStart', 
    function(event, toState, toParams, fromState, fromParams){

      // here check if route can be display (synchronously)
      // or event.preventDefault()

      Auth.isLoggedInAsync(function(loggedIn) {
      if (loggedIn) {
        // continue to original route or go to state by server data
      } else {
        // redirect to login page
      }  
});

您可以在我的解决方案here

中受到启发