请先了解Promise的使用方法,再阅读本文,能坚持到最后才能有所收获。
Promise到底做了什么?
Promise状态只转换一次
问题: 我们知道Promise有三种状态,分别是pending/reslove/reject,一旦从pending转成resolve或reject,即成功了以后即便再执行reject('failed')状态也不会改变
function excuteOnce(then) {
var runs = 0;
function run(fn) {
//1. new Promise 第一步 限制次数
return function (value) {
if(runs++ > 0) return
fn(value)
}
}
then(
run(function() { alert('success') }),
run(function() { alert('error') })
)
}
//executor是 new Promise((resolve, reject) => {})这个参数
excuteOnce(executor)
解决问题:我们使用闭包来访问外部的变量就可以解决只执行一次的问题
resolve和reject为什么可以传参到then
var self = this, resolvers = [], rejecters = [], resolveCurrent = handle(resolvers, true), rejectCurrent = handle(rejecters, false)
var instance = self._instance = { resolvers: resolvers, rejecters: rejecters }
function handle(list, shouldAbsorb) {
return function execute(value) {
try {
setTimeout(function() {
//执行异步操作 -> 执行回调函数队列 -> 重置队列
for(var i = 0; i < list.length; i++) list[i](value)
resolvers.length = rejecters.length = 0
instance.state = shouldAbsorb
//then就是通过这个闭包来访问上一个数据的
//当然他必须先调用resolve和reject回调函数
instance.retry = function() { execute(value) }
})
}catch(e) {
rejectCurrent(e)
}
}
}
function executeOnce(then) {
//以上省略代码...
var onerror = run(rejectCurrent)
try { then(run(resolveCurrent), onerror) } catch(e) { onerror(e) }
}
new Promise通过定义一个retry回调函数来传参
then为什么可以链式调用
PromisePolyfill.prototype.then = function(onFulfilled, onRejection) {
//创建一个新的Promise作为下一个返回值,所以可以链式调用
var resolveNext, rejectNext
var promise = new PromisePolyfill(function(resolve, reject){ resolveNext = resolve, rejectNext = reject })
return promise
}
我们提供一个全新的Promise作为返回值,所以可以链式调用
then如何获取上一个Promise传入的数据?
PromisePolyfill.prototype.then = function(onFulfilled, onRejection) {
var self = this
function handle(callback, list, next, state) {
//2. 第二步,入队
list.push(function(value) { //retry回调函数传过来的值
//传入下一个Promise
try { resolveNext(callback(value)) } catch(e) { if(rejectNext) rejectNext(value) }
})
//3. 第三步,执行retry,他会执行retry -> retry会执行list队列
if(typeof instance.retry === "function" && instance.state === state) instance.retry()
}
//省略代码...
handle(onFulfilled, self.resolvers, resolveNext, true)
handle(onRejection, self.rejecters, rejectNext, false)
}
- 第一步:list.push添加一个回调函数
- 第二步:执行之前的retry回调函数,retry通过闭包保存之前的变量以及作用域
- 第三步:重新执行execute,执行list队列,重新定义retry函数给下一个then来调用
- 第四步:list队列执行回调函数,传入新的Promise(resolve(1))
总结
以上手写一个Promise,可能会有考虑不周的情况出现,还有一种情况没有考虑进去
- then(() => new Promise((resolve, reject) => resolve(1)))