我始终认为要想真正的理解一个API也好,内置对象也罢,最好的方式就是手写一遍。
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
function MyPromise() {
//保存初始化状态
let selt = this;
//初始化状态
this.state = PENDING;
//用于保存resolve或者rejected传入的值
this.value = null;
//用于保存resolve的回调函数
this.resolvedCallbacks = [];
//用于保存reject的回调函数
this.rejectedCallbacks = [];
//状态转变为resolved的方法
function resolve(value) {
//判断传入的元素是否为Promise值,如果是,则状态改变必须等待前一个状态改变后再进行改变
if (value instanceof MyPromise) {
return value.then(resolve, reject);
}
//保证代码的执行顺序为本轮事件循环的末尾
setTimeout(() => {
//只有状态为pending时才能转变
if (self.state === PENDING) {
//修改状态
self.state = RESOLVED;
//设置传入的值
self.value = value;
//执行回调函数
self.resolvedCallbacks.forEach((callback) => {
callback(value);
});
}
}, 0);
}
//状态转变为rejected方法
function reject(value) {
//保证代码的执行顺序为本轮事件循环的末尾
setTimeout(() => {
//只有状态为pending时才能转变
if (self.state === PENDING) {
//修改状态
self.state = REJECTED;
//设置传入的值
self.value = value;
//执行回调函数
self.rejectedCallbacks.forEach((callback) => {
callback(value);
});
}
}, 0);
}
//将两个方法传入函数执行
try {
fn(resolve, reject);
} catch (e) {
//遇到错误时,捕获错误,执行reject函数
reject(e);
}
MyPromise.prototype.then = function (onResolved, onRejected) {
//首先判断两个参数是否为函数类型,因为这两个参数是可选参数
onResolved =
typeof onResolved === "function"
? onResolved
: function (value) {
return value;
};
onRejected =
typeof onRejected === "function"
? onRejected
: function (error) {
throw error;
};
//如果是等待状态,则将函数加入对应列表中
if (this.state === PENDING) {
this.resolvedCallbacks.push(onResolved);
this.rejectedCallbacks.push(onRejected);
}
//如果状态已经凝固,则直接执行对应状态的函数
if (this.state === RESOLVED) {
onResolved(this.value);
}
if (this.state === REJECTED) {
onRejected(this.value);
}
};
}
then
方法返回一个新的Promise
实例,为了在Promise
状态发生变化时再执行then
里的函数,我们使用一个callbacks
数组先把传给then
的函数暂存起来,等状态改变时再调用
那么,怎么保证后一个then里的方法在前一个then(可能是异步)结束之后再执行呢?
我们可以将传给then
函数和新Promise
的resolve
一起push
到前一个Promise
的callbacks
数组中,达到承前启后的效果:
Promise
完成后,调用其resolve
变更状态,在这个resolve里会依次调用callbacks
里的回调,这样就执行了then
里的方法then
里的方法执行完成后,返回一个结果,如果这个结果是个简单的值,就直接调用新Promise
的resolve
,让其状态变更,这又会依次调用新Promise
的callbacks
数组里的方法,循环往复。如果返回的结果是个Promise
,则需要等它完成之后再出发新Promise
的resolve
,所以可在其结果的then
里调用新Promise
的resolve
then(onFulfilled, onReject) {
//保存前一个Promise的this
const self = this;
return new MyPromise((resolve, reject) => {
//封装前一个Promise成功时执行的函数
let fulfilled = () => {
try {
const result = onFulfilled(self.value); //承前
return result instanceof MyPromise
? result.then(resolve, reject)
: resolve(result); //启后
} catch (e) {
reject(e);
}
};
//封装前一个Promise失败时执行的函数
let rejected = () => {
try {
const result = onRejected(self.reason);
return result instanceof MyPromise
? result.then(resolve, reject)
: reject(result);
} catch (e) {
reject(e);
}
};
switch (self.status) {
case PENDING:
self.onFulfilledCallbacks.push(fulfilled);
self.onRejectedCallbacks.push(rejected);
break;
case FULFILLED:
fulfilled();
break;
case REJECT:
rejected();
break;
}
});
};
注意:
then
里的回调方法是同步注册的,但注册到了不同的callbacks
数组中,因为每次then
都返回新的Promise
实例callbacks
数组中提前注册的回调 function promiseAll(promises){
return new Promise(function(resolve, reject){
if(!Array.isArray(promises)){
throw new TypeError(`argument must be a array`)
}
let resolvedCounter =0;//已resolve的promise数
let promiseNum=promises.length;
let resolvedResult =[];//暂存resolve结果的数组
for(let i=0;i<promiseNum;i++){
Promise.resolve(promises[i]).then(value=>{
resolvedCounter++;
resolvedResult[i]=value;
if(resolvedCounter==promiseNum){
return resolve(resolvedResult)
}
},error=>{
return reject(error)
})
}
})
}
//test
let p1=new Promise(function(resolve, reject){
setTimeout(function(){
resolve(1)
},1000)
});
let p2=new Promise(function(resolve, reject){
setTimeout(function(){
resolve(2)
},2000)
});
let p3=new Promise(function(resolve, reject){
setTimeout(function(){
resolve(3)
},3000)
});
promiseAll([p3,p1,p2]).then(res=>{
console.log(res);//[3,1,2]
})
该方法的参数是Promise实例数组,然后其then注册的回调方法是数组中的某一个Promise的状态变为fufilled的时候执行。因为Promise的状态只能改变一次,那么我们只需要把Promise.race中产生的Promise对象的resolve,注入到数组中的每一个Promise实例中的回调函数即可。
Promise.race=function (args){
return new Promise((resolve,reject)=>{
for(let i=0,len=args.length;i<len;i++){
args[i].then(resolve, reject)
}
})
}
finally (onFinally) {
return new Promise((resolve, reject) => {
this.then((result) => {
onFinally();
resolve(result);
}, (reason) => {
onFinally();
reject(reason);
});
});
}