【问题标题】:Promise not resolved after a validation failure验证失败后未解决的承诺
【发布时间】:2017-07-07 09:28:14
【问题描述】:

我有一个通过 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
   };
 });

现在发生的情况是,当我第一次访问表单并提交具有有效结果的表单时,登录过程成功,我被重定向到“详细信息”。但是如果用户名或密码出错并且表单被拒绝,则错误出现了。

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

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

【问题讨论】:

    标签: javascript angularjs promise angular-promise deferred


    【解决方案1】:

    正如@Akis 所说,您只创建了一次 deferred,所以一旦它被履行(或被拒绝)一次,就是这样,永远为了那个承诺。这是因为一个 Promise 只能“解决”一次(履行或拒绝)

    附:讨厌...承诺的语言 - 已解决的承诺意味着履行或拒绝 - 但大多数示例使用名称 resolve 来履行!

    我添加了这个答案,因为您根本不需要使用 deferred,因为 $http 清楚地返回了一个承诺 - 在这种情况下使用 deferred(或 new Promise 构造函数)被认为是一种反模式

    还要注意,我在执行 $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
        };
    });
    

    【讨论】:

      【解决方案2】:

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

      尝试在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 ,那行得通。老实说,我对承诺概念感到非常困惑。但这清楚了很多。不需要负分。我是 Angular 和堆栈溢出的新手。:(
      • @ronit 顺便说一句,投反对票的不是我:D 你的问题很好
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-03-16
      • 2020-10-22
      • 2014-12-15
      • 2016-04-05
      • 2017-03-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多