Phargelm Phargelm - 4 months ago 15
Javascript Question

How deffered object notifies its promise that it has been resolved?

I mean that if there is a way by which deffered object notifies its promise about state changes, therefore anyone can trigger callbacks attached to promise by the same way. I guess, that I'm missing something in my reasonings, but I can't figure out what exactly.

Answer

The promise that jQuery's Deferred returns does not have access to the resolution mechanism; the resolution mechanism in the Deferred does have access to the promise and/or its registered callbacks.

Consider:

// A D object is a bit like a Deferred
function D() {
  // All of these vars are private
  var state = "pending";
  var resolvedValue = null;
  var callbacks = [];
  // This is our promise, which is private
  var p = {
    then: function(callback) {
      callbacks.push(callback);
    }
  };
  
  // Accessor for our promise
  this.promise = function() {
    return p;
  };
  
  // Resolver -- note the promise object doesn't
  // offer any access to this, just the D
  this.resolve = function(value) {
    if (state === "pending") {
      state = "resolved";
      resolvedValue = value;
      // Note that the resolver has access to the callbacks
      // that the promise registers
      setTimeout(function() {
        callbacks.forEach(function(callback) {
          try {
            callback(resolvedValue);
          } catch (e) {
          }
        });
      }, 0);
    }
  };
}

// Usage
var d = new D();
d.promise().then(function(value) {
  console.log("Got " + value);
});
d.resolve("foo");

That is not meant to be any kind of real Deferred implementation, it just is meant to demonstrate how the deferred can access the promise without the promise being able to resolve the deferred.

You can view the full details of jQuery's Deferred in the source. But note that jQuery's Deferred is a bit outdated; these days, having two separate objects with names (Deferred vs. Promise) is out of fashion. Instead, the JavaScript Promise object accepts an initialization function, and the initialization function receives a resolver function it can use to resolve the promise.1


1 There are still two objects involved: The promise and the execution context created by calling the initializer, but that's getting a bit technical...