Skip to content

Instantly share code, notes, and snippets.

@nfroidure
Last active March 15, 2019 09:51
Show Gist options
  • Save nfroidure/5697689 to your computer and use it in GitHub Desktop.
Save nfroidure/5697689 to your computer and use it in GitHub Desktop.
A simple Promise implementation. Moved to GitHub : https://github.com/nfroidure/Promise/blob/master/Promise.js
var Promise=(function() {
var AWAIT=0, SUCCESS=1, FAIL=-1;
function Promise(logic) {
var promise=this;
promise.solved=AWAIT;
var success=function (value) {
if(AWAIT!==promise.solved)
return;
promise.solved=SUCCESS;
promise.value=value;
if(promise.successCallback)
promise.successCallback(value);
};
var fail=function (error) {
if(AWAIT!==promise.solved)
return;
promise.solved=FAIL;
promise.error=error;
if(promise.failCallback)
promise.failCallback(error);
};
var progress=function (value) {
if(AWAIT!==promise.solved)
return;
if(promise.progressCallback)
promise.progressCallback(error);
};
promise.dispose=logic(success, fail, progress);
}
Promise.prototype.then = function(success, fail, progress) {
var thenSuccess, thenFail, thenProgress, returnValue, promise=this;
var thenPromise=new Promise(function(success,fail,progress) {
thenSuccess=success;
thenFail=fail;
thenProgress=progress;
});
var successLogic=function() {
if(success)
returnValue=success(promise.value);
if(returnValue instanceof Promise) {
returnValue.then(thenSuccess, thenFail, thenProgress);
} else {
thenSuccess(returnValue);
}
};
var failLogic=function() {
if(fail)
returnValue=fail(promise.error);
thenFail&&thenFail(returnValue.error);
};
if(AWAIT===this.solved) {
this.successCallback=successLogic;
this.failCallback=failLogic;
this.progressCallback=progress;
} else if(SUCCESS===this.solved) {
setTimeout(successLogic,0);
} else {
setTimeout(failLogic,0);
}
return thenPromise;
};
Promise.all=function () {
var promises=Array.prototype.slice.call(arguments,0),
solved=0,
returnValues=new Array(promises.length);
return new Promise(function(successCallback,errorCallback) {
var promiseDispose=function() {
promises.forEach(function(p) {
AWAIT===p.solved&&p.dispose&&p.dispose();
});
};
var promiseSuccess=function(promise,index) {
return function(value) {
if(solved<promises.length) {
returnValues[index]=value;
solved++;
if(solved==promises.length)
successCallback(returnValues);
}
}
};
var promiseError=function(promise,index) {
return function(error) {
if(solved<promises.length) {
errorCallback(error);
solved=promises.length;
}
}
};
promises.forEach(function(promise,index){
promise.then(promiseSuccess(promise,index),
promiseError(promise,index));
});
return promiseDispose;
});
};
Promise.any=function () {
var promises=Array.prototype.slice.call(arguments,0);
var errors=0;
return new Promise(function(successCallback,errorCallback) {
var promiseDispose=function() {
promises.forEach(function(p) {
AWAIT===p.solved&&p.dispose&&p.dispose();
});
};
var promiseSuccess=function(value) {
successCallback(value);
promiseDispose();
};
var promiseError=function(error) {
if(++errors===promises.length)
errorCallback(error);
};
promises.forEach(function(promise,index){
promise.then(promiseSuccess,promiseError);
});
return promiseDispose;
});
};
return Promise;
})();
// Simple tests
// sync resolution
var p=new Promise(function myPromiseLogic(success, error, progress) {
success(1);
}).then(function(value){
return value+1;
}).then(function(value) {
console.log(value);
});
// output : 2
// async resolution
var p=new Promise(function myPromiseLogic(success, error, progress) {
setTimeout(function() { success(1); },0);
}).then(function(value){
return value+1;
}).then(function(value) {
console.log(value);
});
// output : 2
// return promise
var p=new Promise(function myPromiseLogic(success,error,progress) {
success(1);
}).then(function(value){
return new Promise(function myPromiseLogic(success,error,progress) {
success(value+1);
});
}).then(function(value) {
console.log(value);
});
// output : 2
// Event promise generator
function getEventPromise(type, element, capture, iterations) {
iterations=iterations||1;
return new Promise(function(success,error) {
var eventHandler=function(event) {
iterations--;
if(iterations<1) {
success(event);
dispose();
}
};
var dispose=function() {
element.removeEventListener(type, eventHandler, capture);
};
element.addEventListener(type, eventHandler, capture);
return dispose;
});
}
// USAGE
// Simple event promise
getEventPromise('click',document).then(function () {
console.log('Clicked');
});
// Chaining
getEventPromise('keydown',document).then(function () {
return getEventPromise('click',document,false,2);
}).then(function () {
return getEventPromise('mousemove',document);
}).then(function () {
console.log('Keydown + click twice + mousemove sequentially')
});
// All
Promise.all(
getEventPromise('click',document),
getEventPromise('keyup',document),
getEventPromise('mousemove',document)
).then(function() {
console.log('Keyup + click + mousemove')
});
// Any
Promise.any(
getEventPromise('click',document),
getEventPromise('keyup',document),
getEventPromise('mousemove',document)
).then(function() {
console.log('Keyup | click | mousemove')
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment