Skip to content

Instantly share code, notes, and snippets.

@benjamingr
Created January 19, 2015 21:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benjamingr/f105209f1a6274aad550 to your computer and use it in GitHub Desktop.
Save benjamingr/f105209f1a6274aad550 to your computer and use it in GitHub Desktop.
Got bored without internet
let once = (fns, called) => // fns is an array of functions, called is undefined if first call
fns.map(orig => function OnceBinded(){
if(called) return; else called = true;
return orig(...arguments);
});
export class Promise {
constructor(resolver){
Object.assign(this, {_handlers: [] , _state : State.Pending, _value: null});
resolver(value => {
if(this._state !== State.Pending) return;
this.assume(value, false, (rej, value) => {
this._changeState(rej ? State.Rejected : State.Fulfilled, value);
});
}, err => (this._state === State.Pending) && this._changeState(State.Rejected, err));
}
assume(value, isRejected, cb){
let [res, rej] = once([v => this.assume(v, false, cb), e => this.assume(e, true, cb)]);
try {
let then = value && value.then;
if(typeof then === "function" && Object(value) === value) then.call(value, res, rej);
else cb(isRejected, value);
} catch(e) {
rej(e);
}
}
_changeState(to, value){
Object.assign(this, {_state: to, _value: value});
this._resolve();
}
_resolve(){
let [rejected, fulfilled] = [this._state === State.Rejected, this._state === State.Fulfilled];
Promise._async(() => {
for(let {resolve, reject, onFulfilled, onRejected, p} of this._handlers.splice(0)){
var rejectHandler = (typeof onRejected === "function") && onRejected;
var fulfilledHandler = (typeof onFulfilled === "function") && onFulfilled;
try {
if((rejected && rejectHandler) || (fulfilled && fulfilledHandler)){
let value = (rejected? rejectHandler : fulfilledHandler)(this._value)
if(value === p) throw new TypeError("Recursive assimilation detected");
this.assume(value, false, (rej, val) => rej ? reject(val) : resolve(val));
} else if(rejected) reject(this._value);
else if(fulfilled) resolve(this._value);
} catch(e) {
reject(e);
}
}
});
}
then(onFulfilled, onRejected){
let resolve, reject;
let p = new Promise((res, rej) => [resolve, reject] = [res, rej]);
this._handlers.push({onFulfilled, onRejected, resolve, reject, p});
if(this._state !== State.Pending) this._resolve();
return p;
}
}
let State = Promise.PromiseState = {Rejected: -1, Fulfilled: 1, Pending: 0};
Promise.resolve = val => new Promise(r => r(val));
Promise.reject = val => new Promise((_, r) => r(val));
Promise._async = fn => process.nextTick(fn);
Promise.prototype.catch = function(onRejected){ return this.then(null, onRejected); };
Promise.delay = (ms, val) => new Promise(resolve => setTimeout(() => resolve(val), ms));
Promise.all = arr => new Promise((resolve, reject) => {
let [count, results] = [arr.length, Array(arr.length)];
arr.forEach((x, i) => x.then(val => {
results[i] = val;
if(--count === 0) resolve(results);
}, reject));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment