Source: promise.js

var Q = require('q'),
    _ = require('underscore')._;

/**
 * Promises/A+ spec compliant class, with a little extension
 * http://promises-aplus.github.io/promises-spec/
 *
 * @class Promise
 * @constructor
 * @param {Promise.<T>|T} o - Object to wrap with promise
 * @template T
 */
var Promise = function(o) {
  this._promise = Q(o);
};

/**
 * @callback FulfilledCallback
 * @param {T} result - Fulfilled value
 * @returns {S}
 * @template T,S
 */

/**
 * @callback RejectedCallback
 * @param {Error} reason - Rejected reason
 * @returns {S}
 * @template S
 */

/**
 * The "then" method from the Promises/A+ specification
 *
 * @param {FulfilledCallback.<T, S1>} [onFulfilled]
 * @param {RejectedCallback.<S2>} [onRejected]
 * @returns {Promise.<S1|S2>}
 */
Promise.prototype.then = function() {
  // Delegate Q promise implementation and wrap by our Promise instance
  return new Promise(this._promise.then.apply(this._promise, arguments));
};

/**
 * Call "then" using given node-style callback function
 *
 * @param {Callback.<T>} [callback] - Callback function
 * @returns {Promise.<T>}
 */
Promise.prototype.thenCall = function(callback) {
  return _.isFunction(callback) ? this.then(function(res) {
    return callback(null, res);
  }, function(err) {
    return callback(err);
  }) : this;
};

/**
 * A sugar method, equivalent to promise.then(undefined, onRejected).
 *
 * @param {RejectedCallback.<S>} onRejected
 * @returns {Promise.<S>}
 */
Promise.prototype.fail = function() {
  return new Promise(this._promise.fail.apply(this._promise, arguments));
};

/**
 * Alias for completion
 *
 * @param {FulfilledCallback.<T, S>} [onFulfilled]
 * @returns {Promise.<S>}
 */
Promise.prototype.done = function() {
  return new Promise(this._promise.done.apply(this._promise, arguments));
};

/**
 * @param {...Promise.<*>} p
 */
Promise.when = function() {
  return new Promise(Q.when.apply(Q, arguments));
};

/**
 * Returns rejecting promise with given reason
 *
 * @param {Error} reason - Rejecting reason
 * @returns {Promise}
 */
Promise.reject = function(reason) {
  return new Promise(Q.reject(reason));
};

/**
 * Returns a promise that is fulfilled with an array containing the fulfillment value of each promise, 
 * or is rejected with the same rejection reason as the first promise to be rejected.
 *
 * @param {Array.<Promise.<*>|*>} promises
 * @returns {Promise.<Array.<*>>}
 */
Promise.all = function() {
  return new Promise(Q.all.apply(Q, arguments));
};

/**
 * Returns a deferred object
 *
 * @returns {Deferred}
 */
Promise.defer = function() {
  return new Deferred();
};

/**
 * Deferred object
 *
 * @protected
 * @constructor
 */
var Deferred = function() {
  this._deferred = Q.defer();
  this.promise = new Promise(this._deferred.promise);
};

/**
 * Resolve promise
 * @param {*} result - Resolving result
 */
Deferred.prototype.resolve = function() {
  return this._deferred.resolve.apply(this._promise, arguments);
};

/**
 * Reject promise
 * @param {Error} error - Rejecting reason
 */
Deferred.prototype.reject = function() {
  return this._deferred.reject.apply(this._promise, arguments);
};

/**
 *
 */
module.exports = Promise;