0

I want to resolve a promise object the same way it would be done Angular's defer.resolve with the Javascript Promise object. Put another way: I want to create a dummy promise object to be returned. This promise will be resolved later on.

In Angular I would write it this way:

...
$scope.checkThis = { test: false };

function getPromise() {
    var deferred = $q.defer();
    var data = [1, 2, 3];

    function resolvePromise() {
        deferred.resolve(data);
    }

    $scope.$watch("checkThis.test", function(newVal, oldVal) {
        if (newVal) {
            resolvePromise();
        }
    });

    return deferred.promise;
}

$scope.getData1 = function() {
    return getPromise();
};

$scope.getData2 = function() {
    return getPromise();
};

...

How would I achieve the same with the plain Javascript Promise object? I don't see how to use the Promise constructor as there is one event ($scope.checkThis.test becoming true) that will trigger several resolve.

casenonsensitive
  • 955
  • 2
  • 9
  • 18
  • What do you mean by "*event that will trigger several resolve*"? Why would that work for deferreds but not for the promise constructor? – Bergi Sep 23 '16 at 09:02

1 Answers1

3

Standard promises use the revealing constructor pattern. There is a straightforward and preferred way to do it:

function getPromise() {
  return new Promise(resolve => {
    var data = [1, 2, 3];
    $scope.$watch("checkThis.test", function(newVal, oldVal) {
      if (newVal) {
        resolve(data);
      }
    });
  });
}

Watch out! Standard promises will not trigger an angular digest loop, changes made to scopes inside promise callbacks may not be reflected on the UI and watchers immediately. This is the reason you cannot just change $q promises to standard Promises.

If for some reason you cannot apply the revealing constructor pattern to your scenario, here is a way to create a similar deferred class. Remember, you can always avoid using this class, I am just leaving it here so visitors see how to change from older promise libraries without the need to restructure their existing code. No new code should use this:

class Deferred {
  constructor() {
    this.resolve = null;
    this.reject = null;
    this.promise = null;

    this.promise = new Promise((resolve, reject) => {
      this.resolve = resolve;
      this.reject = reject;
    });
  }
}
Tamas Hegedus
  • 28,755
  • 12
  • 63
  • 97
  • 1
    Well, this `Deferred` class annihilates all the advantages that the revealing constructor pattern has. Don't use it! – Bergi Sep 23 '16 at 09:01
  • If I understand correctly you are creating a Promise factory that returns a pending promise. This works in my case. Thank you. @Bergi: why not use it? – casenonsensitive Sep 23 '16 at 09:21
  • @Bergi Totally right. I only use it in scenarios where there is a distributed system involved, and a message based protocol must be translated to a call-response based one. In that case, the only way to go is to store all the pending requests (as deferreds for example) in a map, and retrieve and resolve them on appropriate response. – Tamas Hegedus Sep 23 '16 at 09:24
  • @casenonsensitive See the link in the answer to Domenic's blog, and [this SO answer](http://stackoverflow.com/a/28692824/1048572) – Bergi Sep 23 '16 at 09:30
  • @casenonsensitive It's less intuitive and less readable. A constructor is meant to bring the object into a usable state. But the `Deferred` constructor does no such thing. You are still required to call `deferred.resolve()` or `deferred.reject()` for the object to actually be usable. Also, those functions can be called anywhere in the program, making it very hard to follow. The Promise constructor guarantees that the resolution/rejection conditions are all in the same place, and the object you can back from `new Promise` is a perfectly usable Promise. – Madara's Ghost Sep 23 '16 at 09:30
  • @TamasHegedus Even there you hardly need deferreds. You will only need to store the `resolve` function, not a reference to the promise itself, and doing the storing operation from within the promise constructor executor is much more direct and safer than creating an intermediate deferred object. – Bergi Sep 23 '16 at 09:32