0

In my webapp, I write a factory methods for serving ajax calls and returning promises by using the $q service. As you can probably tell, I am still on the learning curve of using AngularJS; I found something interesting on the $q.defer() object, which cannot be shared by factory methods. I write the following fake ajax calls in a factory component (plnker here):

(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

  }

}());

In my controller, I have the following:

(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   

  }
}());

In my template, I have the following two buttons that invoke the above two functions in the controller.

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

In the factory AjaxPromiseService component, the var deferred object cannot be shared between the two functions inside the factory, and I have to define a deferred object for each function, otherwise it wouldn't work. So I was wondering why deferred cannot be shared between methods in a factory?

TonyW
  • 18,375
  • 42
  • 110
  • 183

3 Answers3

3

Why deferred cannot be shared between methods?

Because a Deferred object is linked to the promise it resolves. Each promise needs its own one. If you share a single deferred, each method would return the same promise.

See also What are the differences between Deferred, Promise and Future in JavaScript?.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

actually you can share the deferred object. Just think about it not as a service, but a simple JS object. One deferred object can be resolved only once, that's done for purpose. In your AjaxPromiseService you obviously need two differend deferreds, because you resolve them with different data.

for example, $http.post() every time returns different deferred objects

sharing of one deferred between several functions is useful when your deferral can be resolved from different sources (for example you try to get some data simultaneously from localStorage cache, http source and some WebWorker, that is calculating this data)

v1vendi
  • 603
  • 4
  • 9
1

If i understand you correctly you want to reuse the same object created by $q.defer().

$q.defer() returns an object that will be resolved at some point in the future by calling the .resolve method. So basically it represents a certain action that will be completed at some point in the future.

You cannot share the same promise object for multiple actions that complete in the future. See also the link in Bergi's anwser.

Also you plunker is broken because

 var methodObj = {getDummyData : getDummyData};

is missing the getName I fixed it in this plunker

Patrick
  • 361
  • 2
  • 12