Skip to content

Instantly share code, notes, and snippets.

@unscriptable
Created February 7, 2011 06:02
Show Gist options
  • Star 68 You must be signed in to star a gist
  • Fork 22 You must be signed in to fork a gist
  • Save unscriptable/814052 to your computer and use it in GitHub Desktop.
Save unscriptable/814052 to your computer and use it in GitHub Desktop.
A minimalist implementation of a javascript promise
// (c) copyright unscriptable.com / John Hann
// License MIT
// For more robust promises, see https://github.com/briancavalier/when.js.
function Promise () {
this._thens = [];
}
Promise.prototype = {
/* This is the "front end" API. */
// then(onResolve, onReject): Code waiting for this promise uses the
// then() method to be notified when the promise is complete. There
// are two completion callbacks: onReject and onResolve. A more
// robust promise implementation will also have an onProgress handler.
then: function (onResolve, onReject) {
// capture calls to then()
this._thens.push({ resolve: onResolve, reject: onReject });
},
// Some promise implementations also have a cancel() front end API that
// calls all of the onReject() callbacks (aka a "cancelable promise").
// cancel: function (reason) {},
/* This is the "back end" API. */
// resolve(resolvedValue): The resolve() method is called when a promise
// is resolved (duh). The resolved value (if any) is passed by the resolver
// to this method. All waiting onResolve callbacks are called
// and any future ones are, too, each being passed the resolved value.
resolve: function (val) { this._complete('resolve', val); },
// reject(exception): The reject() method is called when a promise cannot
// be resolved. Typically, you'd pass an exception as the single parameter,
// but any other argument, including none at all, is acceptable.
// All waiting and all future onReject callbacks are called when reject()
// is called and are passed the exception parameter.
reject: function (ex) { this._complete('reject', ex); },
// Some promises may have a progress handler. The back end API to signal a
// progress "event" has a single parameter. The contents of this parameter
// could be just about anything and is specific to your implementation.
// progress: function (data) {},
/* "Private" methods. */
_complete: function (which, arg) {
// switch over to sync then()
this.then = which === 'resolve' ?
function (resolve, reject) { resolve && resolve(arg); } :
function (resolve, reject) { reject && reject(arg); };
// disallow multiple calls to resolve or reject
this.resolve = this.reject =
function () { throw new Error('Promise already completed.'); };
// complete all waiting (async) then()s
var aThen, i = 0;
while (aThen = this._thens[i++]) { aThen[which] && aThen[which](arg); }
delete this._thens;
}
};
@matthieusieben
Copy link

matthieusieben commented Aug 8, 2017

How about one that is chainable, that returns an actual instance ?

function P (cb) {
  var q = [], v, u, ok, complete = function (m, r) {
    if (q) {
      var i = -1, l = q;
      ok = !m; v = r; q = null;
      while (++i < l.length) l[i][m](v);
    }
  };

  cb(complete.bind(u, 0), complete.bind(u, 1));

  this.then = then;
  this.catch = then.bind(u, u)

  function then(success, error) {
    return new P(function (resolve, reject) {
      if (q) q.push([ done.bind(u, success), done.bind(u, error) ]);
      else done(ok ? success : error);

      function done (cb) { try {
        var val = cb ? cb(v) : u;
        if (val && val.then) val.then(resolve, reject);
        else (cb || ok ? resolve : reject)(val);
      } catch (e) { reject(e) } }
    })
  }
}

@souparno
Copy link

souparno commented Nov 17, 2018

i guess a much more simpler implementation could be this

var Promise = function() {
    var this._callBacks = [];

    this.then = function(fn) {
        _callBacks.push(fn);
        return this;
    }

    this.resolve = function(data, err) {
        this._callBacks[0].call(this, data, err);
        this._callBacks.shift();
    }
}



function readPromise(filename) {
    var promise = new Promise();

    fs.readFile(filename, function(err, data) {
        promise.resolve(data, err);
    });
    return promise;
}

readPromise("./myfile.js")
    .then(function(data, err) {
        //-- do something here -- //
        //-- resolve promise with this.resolve(data, err) -- //
    })
    .then(function(data, err) {
        //-- do something here -- //
    });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment