AngularJS:$q.dedefe()不能由工厂方法共享

AngularJS: the $q.defer() cannot be shared by factory methods

本文关键字:不能 工厂 方法 共享 dedefe AngularJS      更新时间:2023-09-26

在我的webapp中,我编写了一个工厂方法,用于服务ajax调用并使用$q服务返回promise。正如你可能知道的,我仍然在学习使用AngularJS;我在$q.dedefe()对象上发现了一些有趣的东西,它不能由工厂方法共享。我在工厂组件中编写了以下伪ajax调用(此处为plnker):

(function() {
  'use strict';
  angular.module('testAjax')
  .factory('AjaxPromiseService', AjaxPromiseService);
  AjaxPromiseService.$inject = ['$q', '$timeout'];
  function AjaxPromiseService($q, $timeout) {
    //var deferred = $q.defer(); //cannot be claimed for sharing here
    var methodObj = {getDummyData : getDummyData,
      getName: getName
    };
    return methodObj;
    /******************** implementations below **********/
    function getDummyData() {
      var data = {"data" : "dummy data from ajax!"};
      var deferred = $q.defer();
      $timeout(function() {
        deferred.resolve(data);
      }, 3000); //3 seconds
      return deferred.promise;
    } //getDummyData

    function getName() {
      var deferred = $q.defer();
      $timeout(function() {
        deferred.resolve({"name": "my name is john doe!"});
      }, 2000); //2 seconds
      return deferred.promise;
    } //getName
  }
}());

在我的控制器中,我有以下内容:

(function() {
  'use strict';
  angular.module('testAjax', ['ui.router', 'Constants'])
  .controller('testController', testController);
  testController.$inject = ['$log', 'AjaxPromiseService', '$http', '$q', 'URL_CONFIGS'];
  function testController($log, AjaxPromiseService, $http, $q, URL_CONFIGS) {
    $log.info('in the testController');
    var vm = this;
    vm.message = URL_CONFIGS.home;
    vm.getData = function() {
      AjaxPromiseService.getDummyData().then(function(data) {
        vm.message += data.data;
        //$log.info($q);
      }).catch(function(err) {
        $log.info('error in getting data');
      }).finally(function() {
        $log.info('getData is completed');
      }); //getDummyData
    }; //getData

  vm.getName = function() {
    AjaxPromiseService.getName().then(function(data) {
        vm.message += data.name;
        //$log.info($q);
      }).catch(function(err) {
        $log.info('error in getting data');
      }).finally(function() {
        $log.info('getData is completed');
      }); //getDummyData
}; //getName   
  }
}());

在我的模板中,我有以下两个按钮,它们调用控制器中的上述两个函数。

<button class="btn btn-primary" ng-click="contentView.getData()">Get data</button>
    <button class="btn btn-primary" ng-click="contentView.getName()">Get name</button>
    <strong>Message: {{contentView.message}}</strong>

在工厂AjaxPromiseService组件中,var deferred对象不能在工厂内的两个函数之间共享,我必须为每个函数定义一个deferred对象,否则它将无法工作所以我想知道为什么deferred不能在工厂中的方法之间共享

为什么deferred不能在方法之间共享?

因为Deferred对象链接到它解析的promise。每个承诺都需要自己的承诺。如果您共享一个递延,每个方法都将返回相同的承诺。

另请参阅JavaScript中的Deferred、Promise和Future之间的区别是什么?。

实际上您可以共享延迟对象。不要把它看作一个服务,而是一个简单的JS对象。一个延迟对象只能解析一次,这是有目的的。在您的AjaxPromiseService中,您显然需要两个不同的延迟,因为您使用不同的数据来解决它们。

例如,$http.post()每次返回不同的延迟对象

当您的延迟可以从不同的来源解决时,在多个函数之间共享一个延迟是有用的(例如,您试图同时从localStorage缓存、http源和一些计算这些数据的WebWorker中获取一些数据)

如果我理解正确,您希望重用$q.dedefer()创建的相同对象。

$q.delay()返回一个对象,该对象将在将来某个时候通过调用.resolve方法来解析。因此,基本上,它代表了一个将在未来某个时候完成的特定行动。

您不能为将来完成的多个操作共享同一个promise对象。另请参阅Bergi的anwser中的链接。

另外,你的plunker是坏的,因为

 var methodObj = {getDummyData : getDummyData};

缺少getName,我在这个plunker 中修复了它