Promise源码解读(二)-手写promise剩余方法实现
静态resolve函数实现
// 添加静态resolve方法
static resolve (value) {
// 如果参数是MyPromise实例,直接返回这个实例
if (value instanceof MyPromise) return value
return new MyPromise(resolve => resolve(value))
}
静态resolve函数其实是返回一个新的MyPromise实例,并立即执行resolve函数。
静态reject函数实现
// 添加静态reject方法
static reject (value) {
return new MyPromise((resolve ,reject) => reject(value))
}
静态reject函数其实是返回一个新的MyPromise实例,并立即执行reject函数。
catch函数实现
// 添加catch方法
catch (onRejected) {
return this.then(undefined, onRejected)
}
实现思路基本思路:
其实catch函数是then(null, rejection) 的别名,用于指定发生错误时的回调函数。
由于promise处理错误的回调函数只能有一个入口,所以对then函数优化如下:
then(onFulfilled,onRejected){
switch (this.status) {
case MyPromise.PNEDING:
//错误处理队列,只添加一个错误处理回调函数
if(this.rejectCallback.length<1&&MyPromise.isFunction(onRejected)){
this.rejectCallback.push(onRejected);
}
break
case MyPromise.RESOLVED:
onFulfilled(this.value)
break
case MyPromise.REJECTED:
onRejected(this.value)
break
}
return this;
}
效果
new MyPromise(function(reslove,reject){
reject("错误");
}).then((v)=>{
console.log(v)
}).catch((v)=>{
console.log(v+"123") //错误123
}).catch((v)=>{
console.log(v+"456") //不会出现
});
静态函数all
Promise.all 方法的参数不一定是数组,但是必须具有 iterator 接口,且返回的每个成员都是 Promise 实例
最简版本
//添加静态all方法
static all(list){
return new MyPromise((resolve, reject) => {
let value=[];
for(let [i,p] of list.entries()){
p.then((v)=>{
value.push(v)
})
}
resolve(value)
},err=>{
reject(err);
})
}
let p1=MyPromise.resolve("123");
let p2=MyPromise.resolve("456");
let p3=MyPromise.resolve("789");
let p=MyPromise.all([p1,p2,p3]).then((v)=>{
console.log(v)
});
实现思路基本思路:
创建一个容器用来存放多个MyPromise对象转态结束的值,最后在经过MyPromise的resolve函数一次性返回结果。
优化版本
// 添加静态all方法
//添加静态all方法
static all(list){
return new MyPromise((resolve, reject) => {
let values=[];
let count=0;
for(let [i,p] of list.entries()){
// 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
this.resolve(p).then((v)=>{
values[i] = v;
count++;
// 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
if(count===list.length)resolve(values)
})
}
},err=>{
// 有一个被rejected时返回的MyPromise状态就变成rejected
reject(err);
})
}
let p1=new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve("123");
},1000)
})
let p2=MyPromise.resolve("456");
let p3=MyPromise.resolve("789");
let p4="101112";
let p=MyPromise.all([p1,p2,p3,p4]).then((v)=>{
console.log(v)
});
静态race函数
Promise.race 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例
// 添加静态race方法
static race (list) {
return new MyPromise((resolve, reject) => {
for (let p of list) {
// 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
this.resolve(p).then(res => {
resolve(res)
}, err => {
reject(err)
})
}
})
}
实现思路基本思路:
返回一个新的MyPromise,主要传入promise集合有一个状态发生变化,则新的MyPromise状态跟着改变
finally函数
在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。
finally (cb) {
return this.then(
value => MyPromise.resolve(cb()).then(() => value),
reason => MyPromise.resolve(cb()).then(() => { throw reason })
);
}
实现思路基本思路:
利用then函数,主动触发静态resolve函数。
静态any函数(实验性)
TC39 第四阶段草案(Stage 4)
接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和AggregateError类型的实例,它是 Error 的一个子类,用于把单一的错误集合在一起。本质上,这个方法和Promise.all()是相反的。
// 添加静态any方法
static any(list) {
return new MyPromise((resolve, reject) => {
//如果传入的参数是一个空的可迭代对象,则返回一个 已完成(already resolved) 状态的 Promise。
if(list.length===0)resolve();
let count=0;
for (let p of list) {
this.resolve(p).then((v)=>{
//只要传入的迭代对象中的任何一个 promise 变成成功(resolve)状态
resolve(v)
},(v)=>{
count++
let e=new Error("全部错误");
//所有的 promises 都失败,那么返回的 promise 就会 异步地(当调用栈为空时) 变成成功/失败(resolved/reject)状态。
if(count===list.length)reject(e);
})
}
},err=>{
reject(err);
})
}
实现思路基本思路:
参考all函数实现思路
最后
至此文章已经把promise方法除静态方法allSettled函数这个方法留给读者们自由实现。
以下是完整的代码
class MyPromise{
static PNEDING='pending';
static RESOLVED='funfilled';
static REJECTED='rejected';
constructor(executor){
this.status=MyPromise.PNEDING;
this.value=null;
this.resolveCallback=[];
this.rejectCallback=[];
try {
executor(this._resolve.bind(this),this._reject.bind(this));
} catch (error) {
this._reject(error)
}
}
static isFunction(val){
return typeof val=="function";
}
_resolve(value){
if(value instanceof MyPromise){
return value.then(this.resolve.bind(this),this.reject.bind(this))
}
setTimeout(() => {
if(this.status===MyPromise.PNEDING){
this.status=MyPromise.RESOLVED;
this.value=value;
this.resolveCallback.forEach(cb=>this.value=cb(this.value))
}
}, 0);
}
_reject(value){
setTimeout(() => {
if(this.status===MyPromise.PNEDING){
this.status=MyPromise.REJECTED
this.value=value
this.rejectCallback.forEach(cb=>cb(value))
}
}, 0);
}
// 添加静态resolve方法
static resolve (value) {
// 如果参数是MyPromise实例,直接返回这个实例
if (value instanceof MyPromise) return value
return new MyPromise(resolve => resolve(value))
}
// 添加静态reject方法
static reject (value) {
return new MyPromise((resolve ,reject) => reject(value))
}
//添加静态all方法
static all(list){
return new MyPromise((resolve, reject) => {
let values=[];
let count=0;
for(let [i,p] of list.entries()){
// 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
this.resolve(p).then((v)=>{
values[i] = v;
count++;
// 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
if(count===list.length)resolve(values)
})
}
},err=>{
// 有一个被rejected时返回的MyPromise状态就变成rejected
reject(err);
})
}
// 添加静态race方法
static race (list) {
return new MyPromise((resolve, reject) => {
for (let p of list) {
// 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
this.resolve(p).then(res => {
resolve(res)
}, err => {
reject(err)
})
}
})
}
// 添加静态any方法
static any(list) {
return new MyPromise((resolve, reject) => {
if(list.length===0)resolve();
let count=0;
for (let p of list) {
this.resolve(p).then((v)=>{
resolve(v)
},(v)=>{
count++
let e=new Error("全部错误");
if(count===list.length)reject(e);
})
}
},err=>{
reject(err);
})
}
then(onFulfilled,onRejected){
switch (this.status) {
case MyPromise.PNEDING:
this.resolveCallback.push(onFulfilled);
if(this.rejectCallback.length<1&&MyPromise.isFunction(onRejected)){
this.rejectCallback.push(onRejected);
}
break
case MyPromise.RESOLVED:
onFulfilled(this.value)
break
case MyPromise.REJECTED:
onRejected(this.value)
break
}
return this;
}
// 添加catch方法
catch (onRejected) {
return this.then(undefined, onRejected)
}
finally (cb) {
return this.then(
value => MyPromise.resolve(cb()).then(() => value),
reason => MyPromise.resolve(cb()).then(() => { throw reason })
);
}
}