Skip to content

Instantly share code, notes, and snippets.

@composite
Last active August 29, 2015 14:13
Show Gist options
  • Select an option

  • Save composite/2692acee9b28273a3985 to your computer and use it in GitHub Desktop.

Select an option

Save composite/2692acee9b28273a3985 to your computer and use it in GitHub Desktop.
Resolvr.js: A Simply, Event-Oriented Promise in Javascript. Support All major browsers, node.js and setTimeout supported any JS engines. (other Promise Thenables not yet tested.)

Resolvr: loop friendly Promise, Simplified.

NOTE: Resolvr is not besed on Promise spec.

current vertions is 0.3

How to use?

Similar as Promise. and escape from callback hell!

new Resolvr(function(resolve, reject){
	setTimeout(function(){
	    resolve('Hooray!');
	}, 1000);
	console.log("I'm a lazy callback and resolve after a second.");
}).then(function(resolve, reject, text){
    console.log(text);// print "Hooray!" after a second.
});

APIs

Resolvr members

  • new Resolvr(callback): construct with lazy callback like ajax and accept custom arguments.
  • .then(callback): a next or last callback. returns itself, so you can method chain with it.
  • .resolve(arguments...): explicit call current callback was resolved, go to next callback.
  • .reject(arguments...): explicit call current callback was rejected, go to last callback.
  • .pending(fn): You can define event function each before calling callbacks, but you can't call resolve and reject.
  • .catcher(fn): If callback throws error, you can define catch function to handling exception.

Resolvr callback

function(resolve, reject, otherArgs...){//you can pass other arguments via resolve or reject.
    this.resolved;//If before callback was resolved, returns true.
    this.rejected;//If before callback was rejected, return true at the last callback.
    setTimeout(function(){
        resolve();//send to Resolvr object that this callback has been resolved. next callback will fired if exists.
        reject();//send to Resolvr object that this callback has been rejected. skip all next callback and go to last callback.
    }, 1000);
}

Note: pending callback and catcher callback will not pass the resolve and reject argument.

Static members

  • Resolvr.queue(callbackArray): you can make a sequence callbacks. returns Resolvr object with last thenable callback.
  • Resolvr.parallel(callbackArray): you can call callback at a same time, and returns Resolvrobject with last thenable callback.

Is this library is Compatibility with Promise?

Well, currently, "NO". because this is not based on Promise A+ spec.

I was worked that callbacks can return Thenable objects. but not fully tested.

##Changelog

  • (2015-01-20) 0.1 Initial release.
  • (2015-01-21) 0.2A Fixed error handling arguments and common argument discriptor.
  • 0.2B Fixed pending event and static function returns.
  • 0.2C Fixed Exception handling while thenable call when Resolvr flagged as reject.
  • (2015-01-22) 0.3 Thenable callback makes more friendly with Promise. and changed as
 function callback(resolve, reject){
 	this;//will accept similar of Resolvr object but you can accept only these properties:
 	this.resolved;//before callback has been resolved. realonly.
 	this.rejected;//before callback has been rejected. readonly.
 	resolve();//call next callback if Promise was resolved. same as Proimse.
 	reject(); //call last callback if Promise was rejected. same as Proimse except calling last callback.
 }

Delete private util functions make public.

/*!
* Resolvr - A Promise Simply JavaScript Library v0.1
* https://github.com/composite
*
*
* Copyright 2014 Composite (ukjinplant@msn.com)
* Released under the MIT license
*
* Date: 2014-01-20
*/
(function () {
'use strict';
// Examples
Resolvr.queue([ function (resolve, reject) {
setTimeout(function () {
resolve();
console.log(new Date());
}, 1000);
console.log(1000);
}, function (resolve, reject) {
setTimeout(function () {
resolve();
//reject();
console.log(new Date());
}, 2000);
console.log(2000);
}, function (resolve, reject) {
setTimeout(function () {
resolve();
console.log(new Date());
}, 3000);
console.log(3000);
} ]).then(function () {
console.log('QUEUE');
if(this.rejected) {
alert('Abortd.');
return;
}
Resolvr.parallel([ function (resolve, reject) {
setTimeout(function () {
resolve();
console.log(new Date());
}, 1000);
console.log(1000);
return 1;
}, function (resolve, reject) {
setTimeout(function () {
resolve();
console.log(new Date());
}, 2000);
console.log(2000);
return 1;
}, function (resolve, reject) {
setTimeout(function () {
resolve();
console.log(new Date());
}, 3000);
console.log(3000);
return 1;
} ]).then(function () {
console.log('PARELLEL');
});
});
})();
/*!
* Resolvr - A Promise Simply JavaScript Library v0.3
* https://github.com/composite
* usage: new Resolvr(asyncfunc).then(afterfunc);
*
* Copyright 2014 Composite (ukjinplant@msn.com)
* Released under the MIT license
*
* Changelog
* 0.1 Initial release.
* 0.2A Fixed error handling arguments and common argument discriptor.
* 0.2B Fixed pending event and static function returns.
* 0.2C Fixed Exception handling while thenable call when reject.
* 0.3 Thenable callback makes more friendly with Promise. and changed as: (2015-01-22)
* function callback(resolve, reject){
* this;//will accept similar of Resolvr object but you can accept only these properties:
* this.resolved;//before callback has been resolved. realonly.
* this.rejected;//before callback has been rejected. readonly.
* resolve();//call next callback if Promise was resolved. same as Proimse.
* reject(); //call last callback if Promise was rejected. same as Proimse except calling last callback.
* }
* Delete private util functions make public.
*
* Date: 2014-01-20
*/
var Resolvr = (function () {
'use strict';
// is Your browser supports Promise?
//var isPromise = !!window.Promise;
// Resolvr utility
var timeout = setTimeout,
untimeout = clearTimeout,
interval = setInterval,
uninterval = clearInterval,
util = {
//context functoin binder
bind: function(fn, context, abort){
if(!util.isFn(fn)) return;
return function(){
return fn.apply(context, arguments);
//if(abort) throw new AlreadyCalledError(abort);
};
// Resolvr argument definition.
},shifted: function (context, args) {
var result = [].slice.call(args);
result.unshift(util.bind(context.resolve, context, 'resolve'), util.bind(context.reject, context, 'reject'));
return result;
//make sandbox with readonly properties
},readonly: function(context){
return {
count: context.count,
resolved: context.resolved,
rejected: context.rejected
};
// fn is Function?
}, isFn: function (fn) {
return typeof(fn) === 'function';
// promise caller (for internal use)
}, caller: function (context, args, isreject) {
//console.log('calling ' + context.queue.length);
timeout(function () {
try{
var next = context.queue.shift(),
ronly = util.readonly(context),
result;
//pending first
if(!isreject) context.doing[0].apply(ronly, next[1].slice(2));
//after then
try{
result = next ? next[0].apply(ronly, next[0] == context.catched ? next[1].slice(2) : next[1]) : undefined;
}catch(E){
if(!(E instanceof AlreadyCalledError)) throw E;
}
//stack call for parallel
if(result != undefined && result != null && context.queue.length > 1) {
// result is resolvr or Thenable? go promise ahead.
if(result instanceof Resolvr || typeof(result.then) === 'function')
result.then(function () {
util.caller(context);
});
else util.caller(context);
}
}catch(E) {// Error will be reject and catch fn called.
//console.log(context);
//console.error(E);
context.queue.push([context.catched, [E, this]]);
context.reject.call(context, E);
//context.catched[0].apply(context, [E].concat(context.catched[1]));
}
}, 0);
}
};
// Safe Exception: when resolved or reject called, procedure call will be interrupt.
function AlreadyCalledError(type){
this.name = "AlreadyCalledError";
this.message = "function aborted by " + type + " calling.";
}
AlreadyCalledError.prototype = new Error();
AlreadyCalledError.prototype.constructor = AlreadyCalledError;
// Resolvr instance
function Resolvr(fn) {
if(!(this instanceof Resolvr)) return Resolvr.apply(new Resolvr(), arguments);
this.queue = []; // event queue
this.count = 0; // event count
this.catched = function (e) {console.error(e);}; // when error
this.doing = [function () {}, [this]]; // when calling
this.resolved = false;
this.rejected = false;
if(util.isFn(fn)) // regist first calling
this.queue.push([fn, util.shifted(this, [].slice.call(arguments, 1))]);
};
// Resolvr members
Resolvr.prototype = {
// Resolvr.then : fn will calling when resolvr promise has been resolved
then: function (fn) {
//console.log('then ' + this.count);
if(util.isFn(fn))
this.queue.push([fn, util.shifted(this, [].slice.call(arguments, 1))]);
if(!this.count++)
util.caller(this, this.queue);
return this;
// Resolvr.resolve : explicit call that your resolvr promise was resolved.
}, resolve: function () {
//console.log('resolve ' + this.count);
//util.caller(this, this.queue);
if(!--this.count || this.queue.length > 1) {
//console.log(this.count);
this.resolved = !(this.rejected = false);
this.queue[0][1] = util.shifted(this, arguments);
util.caller(this, this.queue);
}
return this;
// Resolvr.catcher : if your call is getting an error, call your fn.
}, catcher: function (fn) {
if(util.isFn(fn))
this.catched = fn;
return this;
// Resolvr.pending : call while promise is calling.
}, pending: function (fn) {
if(util.isFn(fn))
this.doing = [fn, util.shifted(this, arguments)];
return this;
// Resolvr.reject : call when promise is rejected, remaining then will be removed and not fired.
}, reject: function () {
if(!--this.count || this.queue.length > 1) {
//console.log(this.count);
this.rejected = !(this.resolved = false);
this.queue = [this.queue.pop()];
this.queue[0][1] = util.shifted(this, arguments);
util.caller(this, this.queue, true);
}
return this;
}
};
// Resolvr.queue (static) : call your promise step by step and return next promise.
Resolvr.queue = function (fns) {
var pros = new Resolvr(fns[0]);
for(var i=0; i<fns.length; i++) {
if(i+1<fns.length) {
(function (next) {
pros.then(fns[next]);
})(i+1);
}else{
return pros;
}
}
return pros;
};
// Resolvr.parallel (static) : call your promise together and return next promise.
Resolvr.parallel = function (fns) {
var pros = new Resolvr(function () {return fns[0].apply(this, arguments);});
for(var i=0; i<fns.length; i++) {
if(i+1<fns.length) {
(function (next) {
pros.then(function () {return fns[next].apply(this, arguments);});
})(i+1);
}else{
return pros;
}
}
return pros;
};
Resolvr.util = {
timeout: timeout, untimeout: untimeout,
interval: interval, uninterval: uninterval
};
return Resolvr;
//End of Resolvr.js
})();
/*!
* Resolvr - A Promise Simply JavaScript Library v0
* https://github.com/composite
* (for Oldschool browsers)
*
* Copyright 2014 Composite (ukjinplant@msn.com)
* Released under the MIT license
*
* Date: 2014-01-20
*/
(function(){
function Resolvr(fn){
this.start = [];
this.end = [];
this.next.apply(this, arguments);
}
Resolvr.prototype = {
then: function(fn){
//console.log(['then',this.end.length,fn.toString()]);
this.end.push(fn);
if(this.end.length) this.__call();
return this;
},resolve: function(){
//console.log(['resolve',this.end.length, [this].concat(arguments)]);
var fn = this.end.shift(), args = [this].concat(arguments);
if(Resolvr.isF(fn)) setTimeout(function(){fn.apply(args[0], args);}, 0);
if(this.end.length) this.__call();
return this;
},next: function(fn){
//console.log(['next',this.start.length]);
this.start.push([function(){
var args = Resolvr.args(arguments);
args.unshift(this);
if(Resolvr.isF(fn)) setTimeout(function(){fn.apply(args[0], args);}, 0);
}, arguments]);
if(this.end.length) this.__call();
return this;
},__call: function(){
//console.log(['call',this.start.length]);
var start = this.start.shift(), that = this;
if(start&&Resolvr.isF(start[0])) setTimeout(function(){start[0].apply(that, start[1]);}, 0);
}
};Resolvr.args = function(args){[].shift.call(args);return [].concat.call(args,[]);};
Resolvr.queue = function(fns){
var pros = new Resolvr(fns[0]);
for(var i=0; i<fns.length; i++){
if(i+1<fns.length){
(function(next){
pros.then(function(){
//console.log(['queue',next]);
this.next(fns[next]);
});
})(i+1);
}else{
return pros;
}
}
};Resolvr.isF = function(fn){return typeof(fn) === 'function';};
Resolvr.parellel = function(fns){
var pros = new Resolvr(fns[0]);
for(var i=0; i<fns.length; i++){
if(i+1<fns.length){
(function(next){
pros.then(function(){
//console.log(['parellel',next]);
}).next(fns[next]);
})(i+1);
}else{
return pros;
}
}
};
window.Resolvr = Resolvr;
})();
/*!
* Resolvr - A Promise Simply JavaScript Library v0
* https://github.com/composite
* (usage examples)
*
* Copyright 2014 Composite (ukjinplant@msn.com)
* Released under the MIT license
*
* Date: 2014-01-20
*/
Resolvr.queue([
function(pro){setTimeout(function(){pro.resolve();console.log(new Date());}, 1000);console.log(1000);},
function(pro){setTimeout(function(){pro.resolve();console.log(new Date());}, 2000);console.log(2000);},
function(pro){setTimeout(function(){pro.resolve();console.log(new Date());}, 3000);console.log(3000);}
]).then(function(){
console.log('QUEUE');
Resolvr.parellel([
function(pro){setTimeout(function(){pro.resolve();console.log(new Date());}, 1000);console.log(1000);},
function(pro){setTimeout(function(){pro.resolve();console.log(new Date());}, 2000);console.log(2000);},
function(pro){setTimeout(function(){pro.resolve();console.log(new Date());}, 3000);console.log(3000);}
]).then(function(){
console.log('PARELLEL');
});
});
/*!
* Resolvr - A Promise Simply JavaScript Library v0
* https://github.com/composite
* (When=Then Pair version.)
*
* Copyright 2014 Composite (ukjinplant@msn.com)
* Released under the MIT license
*
* Date: 2014-01-20
*/
(function(){
function Resolvr(fn){
this.start = [];
this.end = [];
this.next.apply(this, arguments);
}
Resolvr.prototype = {
then: function(fn){
//console.log(['then',this.end.length,fn.toString()]);
this.end.push(fn);
if(this.end.length) this.__call();
return this;
},resolve: function(){
//console.log(['resolve',this.end.length, [this].concat(arguments)]);
var fn = this.end.shift();
if(Resolvr.isF(fn)) setTimeout(function(args){fn.apply(args[0], args);}, 0, [this].concat(arguments));
if(this.end.length) this.__call();
return this;
},next: function(fn){
//console.log(['next',this.start.length]);
this.start.push([function(){
var args = Resolvr.args(arguments);
args.unshift(this);
if(Resolvr.isF(fn)) setTimeout(function(args){fn.apply(args[0], args);}, 0, args);
}, arguments]);
if(this.end.length) this.__call();
return this;
},__call: function(){
//console.log(['call',this.start.length]);
var start = this.start.shift(), that = this;
if(start&&Resolvr.isF(start[0])) setTimeout(function(arg){arg[0].apply(that, arg[1]);}, 0, start);
}
};Resolvr.args = function(args){[].shift.call(args);return [].concat.call(args,[]);};
Resolvr.queue = function(fns){
var pros = new Resolvr(fns[0]);
for(var i=0; i<fns.length; i++){
if(i+1<fns.length){
(function(next){
pros.then(function(){
//console.log(['queue',next]);
this.next(fns[next]);
});
})(i+1);
}else{
return pros;
}
}
};Resolvr.isF = function(fn){return typeof(fn) === 'function';};
Resolvr.parellel = function(fns){
var pros = new Resolvr(fns[0]);
for(var i=0; i<fns.length; i++){
if(i+1<fns.length){
(function(next){
pros.then(function(){
//console.log(['parellel',next]);
}).next(fns[next]);
})(i+1);
}else{
return pros;
}
}
};
window.Resolvr = Resolvr;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment