Created
April 24, 2018 09:57
-
-
Save mutongwu/79d25a8447b56f33ae35eb13d50d81ac to your computer and use it in GitHub Desktop.
a tiny promise polyfill
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function isThenable(obj){ | |
if(obj && typeof obj.then === 'function'){ | |
return true; | |
} | |
return false; | |
} | |
function ChainedPromise(promise, rv, rj){ | |
this.success = [rv]; | |
this.fail = [rj]; | |
this.promise = promise; | |
this.value = null; | |
} | |
ChainedPromise.prototype = { | |
then: function(rv, rj){ | |
var data = this.promise.data; | |
if(data.state === 2){ | |
if(data.flag){ | |
rv(this.value); | |
}else{ | |
rj(this.value); | |
} | |
}else{ | |
if(rv){ | |
this.success.push(rv); | |
} | |
if(rj){ | |
this.fail.push(rj); | |
} | |
} | |
return this; | |
}, | |
_do: function(val, isResolved){ | |
var _this = this; | |
var jobs = isResolved ? this.success: this.fail; | |
this.value = val; | |
if(jobs.length){ | |
val = (jobs.shift())(this.value); | |
if(isThenable(val)){ | |
val.then(function(res){ | |
_this.resolve(res); | |
}); | |
return; | |
} | |
this.value = val; | |
} | |
setTimeout(function(){ | |
while(jobs.length){ | |
val = (jobs.shift())(_this.value); | |
if(isThenable(val)){ | |
val.then(function(res){ | |
_this.resolve(res); | |
}); | |
break; | |
} | |
_this.value = val; | |
} | |
},0); | |
}, | |
resolve: function(val){ | |
this._do(val, true); | |
}, | |
reject: function(val){ | |
this._do(val, false); | |
} | |
}; | |
function TinyPromise(fn){ | |
var _this = this; | |
this.data = { | |
success:[], | |
fail:[], | |
state:0, // 0:未执行、1:执行中、2:执行完成 | |
flag: null, // true:成功执行;false:失败执行 | |
value:null, | |
chained:[] //链式对象 | |
} | |
// this.chained = new ChainedPromise(this); | |
setTimeout(function(){ | |
fn.call(_this,function(res){ | |
_this._exec(res, true); | |
}, function(res){ | |
_this._exec(res, false); | |
}); | |
},0); | |
} | |
TinyPromise.prototype = { | |
then: function(rv, rj){ | |
var data = this.data; | |
if(data.state === 2){ | |
if(data.flag){ | |
rv(data.value); | |
}else{ | |
rj(data.value); | |
} | |
} | |
if(data.state === 0){ | |
data.state = 1; | |
} | |
var chain = new ChainedPromise(this,rv, rj); | |
data.chained.push(chain); | |
return chain; | |
}, | |
_exec: function (res, isResolved) { | |
var data = this.data; | |
var method = isResolved ? 'resolve': 'reject'; | |
if(data.state !== 2){ | |
data.value = res; | |
data.state = 2; | |
data.flag = !!isResolved; | |
while(data.chained.length){ | |
(data.chained.shift())[method](res); | |
} | |
} | |
} | |
} | |
TinyPromise.resolve = function(value) { | |
if (value && isThenable(value)) { | |
return value; | |
} | |
return new TinyPromise(function(resolve) { | |
resolve(value); | |
}); | |
}; | |
TinyPromise.reject = function(value) { | |
return new TinyPromise(function(resolve, reject) { | |
reject(value); | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment