验证失败后未解决的承诺

Promise not resolved after a validation failure

我有一个通过 promise 对象创建的登录表单。 一切正常,除了形式验证生效的情况。 这是我的 html 文件。

   <form id="signin" class="signinform" autocomplete="off"> 
   <span ng-show="errorName" class="error_block">{{ errorName }}</span>
   <input placeholder="User Name" ng-model="user.name" type="text" name="user_name" required>
   <input placeholder="Password" ng-model="user.password" type="password" name="password" required>
  <input type="submit" ng-click="submit(user)" value="Log IN" id="submit">
</form>

这里是写入ng-click的控制器

  $scope.submit =  function(user){
   LoginService.login(user)
    .then(function(response) {           
         var userInfo = response.userName
         $rootScope.$emit('myEvent',userInfo);
         $location.path("/details/1");
    },
    function(error) {
      $scope.errorName = "Invalid Username or Password";
    });
 }

这是

的工厂服务
app.factory("LoginService", function($http, $q, $window) {
var userInfo;
var deferred = $q.defer();
 function login(user) {
  $http({
   method: 'POST',
   url: "login.php",
   data: { "userName": user.name, "password": user.password },
   headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'}
   }).then(function(result) { 
   userInfo = {
    accessToken: result.data.login.token,
    userName: result.data.login.name
   };
   $window.sessionStorage["userInfo"] = JSON.stringify(userInfo);  
    deferred.resolve(userInfo);
    }, function(error) {
    deferred.reject(error);
   });      
   return deferred.promise;
   }

   return {
    login: login
   };
 });

现在发生的事情是当我第一次访问表单并提交表单并获得有效结果时登录过程成功并且我被重定向到 'details'。但是如果用户名或密码错误并且表单被拒绝显示错误。

然后,如果我输入正确的凭据并点击提交,我不会被重定向到 'details' 并停留在同一个登录表单上,但该错误仍然显示。 但是当我刷新页面时,我已经登录了。那是因为发生了http请求,并且设置了userInfo。

我调试了代码,发现 then 函数没有在我的 $scope.submit 中执行,这可能是因为承诺尚未解决。我尝试了几个 scope.apply 和其他东西,但没有任何效果。 任何人都可以帮助这里发生的事情。

这是因为承诺已经解决了。

尝试在 login 函数中移动您的 var deferred = $q.defer(); 声明。

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

  $http({
   method: 'POST',
   url: "login.php",
   data: { "userName": user.name, "password": user.password },
   headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'}
   }).then(function(result) { 
   userInfo = {
    accessToken: result.data.login.token,
    userName: result.data.login.name
   };
   $window.sessionStorage["userInfo"] = JSON.stringify(userInfo);  
    deferred.resolve(userInfo);
    }, function(error) {
    deferred.reject(error);
   });      
   return deferred.promise;
   }

   return {
    login: login
   };

正如@Akis 所说,您只创建了一次 deferred,所以一旦它被履行(或拒绝)一次,就是这样,永远兑现承诺。这是因为承诺只能 "resolved" 一次(实现或拒绝)

P.S. pet hate ... the language of promises - resolved promise means fulfilled or rejected - but most examples use the name resolve to fulfil!!

我已经添加了这个答案,因为你根本不需要使用 deferred,清楚地看到 $http returns 一个承诺 - 在这种情况下使用 deferred(或 new Promise 构造函数)被认为是 anti-pattern

另请注意,我在 $http 执行之前添加了 $window.sessionStorage.removeItem("userInfo"); - 此时清除 sessionInfo 似乎合乎逻辑

app.factory("LoginService", function($http, $q, $window) {
    function login(user) {
        // added this as it seems it should be done!
        $window.sessionStorage.removeItem("userInfo");
        return $http({
            method: 'POST',
            url: "login.php",
            data: {
                "userName": user.name,
                "password": user.password
            },
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
            }
        }).then(function(result) {
            var userInfo = {
                accessToken: result.data.login.token,
                userName: result.data.login.name
            };
            $window.sessionStorage["userInfo"] = JSON.stringify(userInfo);
            return userInfo;
        });
    }
    return {
        login: login
    };
});