Promise.prototype.then = function()

in jones-promises/lib/Promise.js [132:208]


Promise.prototype.then = function(fulfilled_callback, rejected_callback, progress_callback) {
  var self = this;
  // create a new promise to return from the "then" method
  var new_promise = new Promise();
  if (typeof self.fulfilled_callbacks === 'undefined') {
    self.fulfilled_callbacks = [];
    self.rejected_callbacks = [];
    self.progress_callbacks = [];
  }
  if (self.resolved) {
    var resolved_result;
    if(udebug.is_detail()) { udebug.log(this.name, 'Promise.then resolved; err:', self.err); }
    if (self.err) {
      // this promise was already rejected
      if(udebug.is_detail()) { udebug.log(self.name, 'Promise.then resolved calling (delayed) rejected_callback', rejected_callback); }
      global.setImmediate(function() {
        if(udebug.is_detail()) { udebug.log(self.name, 'Promise.then resolved calling rejected_callback', fulfilled_callback); }
        thenPromiseFulfilledOrRejected(self, rejected_callback, new_promise, self.err, true);
      });
    } else {
      // this promise was already fulfilled, possibly with a null or undefined result
      if(udebug.is_detail()) { udebug.log(self.name, 'Promise.then resolved calling (delayed) fulfilled_callback', fulfilled_callback); }
      global.setImmediate(function() {
        if(udebug.is_detail()) { udebug.log(self.name, 'Promise.then resolved calling fulfilled_callback', fulfilled_callback); }
        thenPromiseFulfilledOrRejected(self, fulfilled_callback, new_promise, self.result);
      });
    }
    return new_promise;
  }
  // create a closure for each fulfilled_callback
  // the closure is a function that when called, calls setImmediate to call the fulfilled_callback with the result
  if (typeof fulfilled_callback === 'function') {
    if(udebug.is_detail()) { udebug.log(self.name, 'Promise.then with fulfilled_callback', fulfilled_callback); }
    // the following function closes (this, fulfilled_callback, new_promise)
    // and is called asynchronously when this promise is fulfilled
    this.fulfilled_callbacks.push(function(result) {
      global.setImmediate(function() {
        thenPromiseFulfilledOrRejected(self, fulfilled_callback, new_promise, result);
      });
    });
  } else {
    if(udebug.is_detail()) { udebug.log(self.name, 'Promise.then with no fulfilled_callback'); }
    // create a dummy function for a missing fulfilled callback per 2.2.7.3 
    // If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value.
    this.fulfilled_callbacks.push(function(result) {
      global.setImmediate(function() {
        thenPromiseFulfilledOrRejected(self, emptyFulfilledCallback, new_promise, result);
      });
    });
  }

  // create a closure for each rejected_callback
  // the closure is a function that when called, calls setImmediate to call the rejected_callback with the error
  if (typeof rejected_callback === 'function') {
    if(udebug.is_detail()) { udebug.log(self.name, 'Promise.then with rejected_callback', rejected_callback); }
    this.rejected_callbacks.push(function(err) {
      global.setImmediate(function() {
        thenPromiseFulfilledOrRejected(self, rejected_callback, new_promise, err);
      });
    });
  } else {
    if(udebug.is_detail()) { udebug.log(self.name, 'Promise.then with no rejected_callback');  }
    // create a dummy function for a missing rejected callback per 2.2.7.4 
    // If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason.
    this.rejected_callbacks.push(function(err) {
      global.setImmediate(function() {
        thenPromiseFulfilledOrRejected(self, emptyRejectedCallback, new_promise, err);
      });
    });
  }
  // todo: progress_callbacks
  if (typeof progress_callback === 'function') {
    this.progress_callbacks.push(progress_callback);
  }

  return new_promise;
};