【问题标题】:How to return a resolved promise from an AngularJS Service using $q?如何使用 $q 从 AngularJS 服务返回已解决的承诺?
【发布时间】:2014-06-27 08:38:21
【问题描述】:

我的服务是:

myApp.service('userService', [
  '$http', '$q', '$rootScope', '$location', function($http, $q, $rootScope, $location) {
    var deferred;
    deferred = $q.defer();
    this.initialized = deferred.promise;
    this.user = {
      access: false
    };
    this.isAuthenticated = function() {
      this.user = {
        first_name: 'First',
        last_name: 'Last',
        email: 'email@address.com',
        access: 'institution'
      };
      return deferred.resolve();
    };
  }
]);

我在我的config 文件中通过以下方式调用它:

myApp.run([
  '$rootScope', 'userService', function($rootScope, userService) {
    return userService.isAuthenticated().then(function(response) {
      if (response.data.user) {
        return $rootScope.$broadcast('login', response.data);
      } else {
        return userService.logout();
      }
    });
  }
]);

但是,它抱怨then 不是一个函数。我不是在返回已解决的承诺吗?

【问题讨论】:

    标签: javascript angularjs promise angular-promise


    【解决方案1】:

    如何在 AngularJS 中简单地返回一个预先解决的承诺

    已解决的承诺:

    return $q.when( someValue );    // angularjs 1.2+
    return $q.resolve( someValue ); // angularjs 1.4+, alias to `when` to match ES6
    

    被拒绝的承诺:

    return $q.reject( someValue );
    

    【讨论】:

    • 这正是我想要的。存根 http 服务调用时返回静态值的好方法。
    【解决方案2】:

    返回你的承诺,返回 deferred.promise。
    它是具有 'then' 方法的 promise API。

    https://docs.angularjs.org/api/ng/service/$q

    调用 resolve 不会返回一个 Promise,它只会发出信号 承诺承诺已解决,因此它可以执行'then'逻辑。

    基本模式如下,冲洗一遍重复
    http://plnkr.co/edit/fJmmEP5xOrEMfLvLWy1h?p=preview

    <!DOCTYPE html>
    <html>
    
    <head>
      <script data-require="angular.js@*" data-semver="1.3.0-beta.5" 
            src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
      <link rel="stylesheet" href="style.css" />
      <script src="script.js"></script>
    </head>
    
    <body>
    
    <div ng-controller="test">
      <button ng-click="test()">test</button>
    </div>
    <script>
      var app = angular.module("app",[]);
    
      app.controller("test",function($scope,$q){
    
        $scope.$test = function(){
          var deferred = $q.defer();
          deferred.resolve("Hi");
          return deferred.promise;
        };
    
        $scope.test=function(){
          $scope.$test()
          .then(function(data){
            console.log(data);
          });
        }      
      });
    
      angular.bootstrap(document,["app"]);
    
    </script>
    

    【讨论】:

    • 那么承诺将如何解决? .then 永远不会被触发
    • @Shamoon deferred.resolve();在您调用它的那一刻就解决了,因为没有给出任何值。我建议不要写 deferred.resolve("Hi");只需编写 deferred.resolve();得到一个已解决的空头承诺。但你也可以使用 $q.when();得到一个可解决的空承诺;-)。
    • 恕我直言,这比接受的答案要好,后者通过使用 $timeout 生成将要解决的承诺无法显示手动创建和解决承诺的机制。
    【解决方案3】:

    要返回已解决的承诺,您可以使用:

    return $q.defer().resolve();
    

    如果您需要解决某些问题或返回数据:

    return $q.defer().resolve(function(){
    
        var data;
        return data;
    
    });
    

    【讨论】:

    • 我有 posted 一个更短的版本。
    【解决方案4】:

    对于较短的 JavaScript 代码,请使用:

    myApp.service('userService', [
      '$q', function($q) {
        this.initialized = $q.when();
        this.user = {
          access: false
        };
        this.isAuthenticated = function() {
          this.user = {
            first_name: 'First',
            last_name: 'Last',
            email: 'email@address.com',
            access: 'institution'
          };
          return this.initialized;
        };
      }
    ]);
    

    您知道您通过用新对象覆盖而不是仅设置对象属性来解除与 userService.user 的绑定吗?

    以下是我的 plnkr.co 示例代码示例(工作示例: http://plnkr.co/edit/zXVcmRKT1TmiBCDL4GsC?p=preview):

    angular.module('myApp', []).service('userService', [
        '$http', '$q', '$rootScope', '$location', function ($http, $q, $rootScope, $location) {
        this.initialized = $q.when(null);
        this.user = {
            access: false
        };
        this.isAuthenticated = function () {
            this.user.first_name = 'First';
            this.user.last_name = 'Last';
            this.user.email = 'email@address.com';
            this.user.access = 'institution';
            return this.initialized;
        };
    }]);
    
    angular.module('myApp').controller('myCtrl', ['$scope', 'userService', function ($scope, userService) {
        $scope.user = userService.user;
        $scope.callUserService = function () {
            userService.isAuthenticated().then(function () {
                $scope.thencalled = true;
            });
        };
    }]);
    

    【讨论】:

      【解决方案5】:

      这是您服务的正确代码:

      myApp.service('userService', [
        '$http', '$q', '$rootScope', '$location', function($http, $q, $rootScope, $location) {
      
          var user = {
            access: false
          };
      
          var me = this;
      
          this.initialized = false;
          this.isAuthenticated = function() {
      
            var deferred = $q.defer();
            user = {
              first_name: 'First',
              last_name: 'Last',
              email: 'email@address.com',
              access: 'institution'
            };
            deferred.resolve(user);
            me.initialized = true;
      
            return deferred.promise;
          };
        }
      ]);
      

      那么你的控制器应该相应地对齐:

      myApp.run([
        '$rootScope', 'userService', function($rootScope, userService) {
          return userService.isAuthenticated().then(function(user) {
            if (user) {
              // You have access to the object you passed in the service, not to the response.
              // You should either put response.data on the user or use a different property.
              return $rootScope.$broadcast('login', user.email);  
            } else {
              return userService.logout();
            }
          });
        }
      ]);
      

      关于服务的几点注意事项:

      • 仅在服务中公开需要公开的内容。用户应保留在内部,并且只能由 getter 访问。

      • 在函数中,使用 'me' 服务来避免 JavaScript 的极端情况。

      • 我猜到了 initialized 的意思,如果我猜错了,请随时纠正我。

      【讨论】:

        【解决方案6】:

        来自您的服务方法:

        function serviceMethod() {
            return $timeout(function() {
                return {
                    property: 'value'
                };
            }, 1000);
        }
        

        在你的控制器中:

        serviceName
            .serviceMethod()
            .then(function(data){
                //handle the success condition here
                var x = data.property
            });
        

        【讨论】:

        • @BenjaminGruenbaum 是的,你是对的,我不知道$timeout 实际上返回了一个承诺,serviceMethod 可以缩短为:return $timeout(function() { return {property: 'value'} ; }, 1000);
        • 这可能有效,但肯定不是推荐的返回承诺的方法
        • @BenjaminGruenbaum 我做了,现在返回 $timeout 生成的承诺。
        • 很好,我收回了我的-1。
        • 啊好吧,但我仍然同意他的观点,即使出于不同的原因!我很欣赏downvote令人沮丧,我们可以使用upvotes来帮助好的内容浮到顶部,但在这种情况下,我觉得你的回答没有帮助,因为它无法解释 $q 的机制,而是提出$q 的抽象。对 Promise 不熟悉的人,或者像我一样熟悉 Promise 但对 Angular 不熟悉的人,可能会完全搞错!
        【解决方案7】:

        试试这个:

        myApp.service('userService', [
            '$http', '$q', '$rootScope', '$location', function($http, $q, $rootScope, $location) {
              var deferred= $q.defer();
              this.user = {
                access: false
              };
              try
              {
              this.isAuthenticated = function() {
                this.user = {
                  first_name: 'First',
                  last_name: 'Last',
                  email: 'email@address.com',
                  access: 'institution'
                };
                deferred.resolve();
              };
            }
            catch
            {
                deferred.reject();
            }
        
            return deferred.promise;
          ]);
        

        【讨论】:

        • 有人能告诉我为什么这被标记为否决吗?
        猜你喜欢
        • 1970-01-01
        • 2016-03-18
        • 2014-09-07
        • 2021-05-25
        • 2018-03-15
        • 2013-05-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多