Promise 的深度理解:如何用 JavaScript 实现Promise

加深对 promise 的理解,一步步实现并完善 promise 及API实现。

resolve 和 reject 实现

resolve 和 reject 用来决定 new Promise 后 promise 对象的状态的,两个函数在代码中的先后顺序决定了 promise 对象的状态。一旦状态改变则不再修改

实现的难点在于状态改变后无法再次修改 promise 的状态。

// promise 中 resolve/reject 执行的例子
console.log('start')
const p1 =new Promise((resolve,reject)=>{
    console.log("doing")
    resolve(1)
    reject(2)
})
console.log('end',p1)
// start
// doing
// end Promise {<fulfilled>: 1}
​
// 手动实现
class MPromise{
    static PENDINGSTATUS ='pending'
    static FULFILLESSTATUS = 'fulfilled'
    static REJECTEDSTATUS = 'rejected'
    constructor(executor){
        this.PromiseState = MPromise.PENDINGSTATUS;
        this.PromiseResult = null;
        // resolve 和 reject 执行时 this 的值为 window,需要绑定 this
        executor(this.resolve.bind(this),this.reject.bind(this))
    }
    resolve(res){
        if(this.PromiseState === MPromise.PENDINGSTATUS){
            this.PromiseResult = res;
            this.PromiseState = MPromise.FULFILLESSTATUS;
        }
    }
    reject(err){
        if(this.PromiseState === MPromise.PENDINGSTATUS){
            this.PromiseResult = err;
            this.PromiseState = MPromise.REJECTEDSTATUS;
        }
    }
}
​
console.log('start')
const p2 =new MPromise((resolve,reject)=>{
    console.log("doing")
    resolve(1)
    reject(2)
})
console.log('end',p2)
// start
// doing
// end MPromise { PromiseState: 'fulfilled', PromiseResult: 1 }
复制代码

Promise.prototype.then 的实现

基本用法

说明

  1. 异步执行
  1. 构造函数的参数 executor 执行时调用 resolve ,then 执行 onFulfilled
  1. 构造函数的参数 executor 执行时调用 reject ,then 执行 onRejected
// 示例
console.log('start')
const p1 = new Promise((resolve, reject) => {
    resolve(1)
}).then(res => {
    console.log('p1->then', res)
})
​
const p2 = new Promise((resolve, reject) => {
    reject(2)
}).then(res => { }, err => {
    console.log('p2->then', err)
})
​
console.log('end')
// start
// end
// p1->then 1
// p2->then 2
复制代码

实现思路:

  1. then 函数用来注册回调函数,将要执行的 onFulfilled, onRejected 回调函数加入到队列中
  2. resolve/reject 函数异步执行回调函数

new Promise(resolve=>resolve(1)).then(res=>res) 为例说明实现过程

  1. pending状态:执行同步代码

    • 执行 resolve=>resolve(1) 函数 ,执行 resolve(1) 函数
    • 需要执行的代码封装成函数 fn 加入到微任务中,该函数功能包括:状态修改为 fulfilled ,PromiseResult 值修改,执行 resolvedQueue 队列中的函数
    • 执行 then(res=>res) 函数,添加 onFulfilled 函数即 res=>res 到队列数组 resolvedQueue 中
  2. pending → fulfilled 状态:微任务中的 fn 异步执行

    • 状态修改为 fulfilled
    • PromiseResult 值修改
    • resolvedQueue 队列中的数组依次执行
class MPromise {
    static PENDINGSTATUS = 'pending'
    static FULFILLESSTATUS = 'fulfilled'
    static REJECTEDSTATUS = 'rejected'
    constructor(executor) {
        this.PromiseState = MPromise.PENDINGSTATUS;
        this.PromiseResult = null;
        // +++ 以下代码块为新增
        // 存放then 函数中需要执行的 onFulfilled, onRejected 回调函数
        this.resolvedQueue = [];
        this.rejectedQueue = [];
        // +++
        // resolve 和 reject 执行时 this 的值为 window,需要绑定 this
        executor(this.resolve.bind(this), this.reject.bind(this));
    }
    resolve(res) {
        if (this.PromiseState === MPromise.PENDINGSTATUS) {
            // 通过if 判断状态,实现无法再次修改 promise 的状态
            // +++ 以下代码块为新增
            // 修改状态(此处为异步),异步执行 resolvedQueue 队列中保存的 onFulfilled 函数
            const fn = () => {
                this.PromiseResult = res;
                this.PromiseState = MPromise.FULFILLESSTATUS;
                this.resolvedQueue.length && this.resolvedQueue.forEach(cb => cb(res))
            }
            // 开启微队列
            resultHandlerAsync(fn)
            // +++
        }
    }
    reject(err) {
        if (this.PromiseState === MPromise.PENDINGSTATUS) {
            // +++ 以下代码块为新增
            // 异步执行 rejectedQueue 队列中保存的 onRejected 函数
            const fn = () => {
                this.PromiseResult = err;
                this.PromiseState = MPromise.REJECTEDSTATUS;
                this.rejectedQueue.length && this.rejectedQueue.forEach(cb => cb(err))
            }
            // 开启微队列
            resultHandlerAsync(fn)
            // +++
        }
    }
    // +++ 以下代码块为新增
    then(onFulfilled, onRejected) {
        // then 函数用来注册回调函数,将要执行的 onFulfilled, onRejected 回调函数加入到队列中
        if (this.PromiseState === MPromise.PENDINGSTATUS) {
            this.resolvedQueue.push(onFulfilled)
            this.rejectedQueue.push(onRejected)
        }
    }
    // +++

}

// 测试
console.log('start')
const p3 = new MPromise((resolve, reject) => {
    resolve(1)
}).then(res => {
    console.log('p3->then', res)
})

const p4 = new MPromise((resolve, reject) => {
    reject(2)
}).then(res => { }, err => {
    console.log('p4->then', err)
})

console.log('end')
// start
// end
// p3->then 1
// p4->then 2
复制代码

then 的链式调用

需要实现的功能如下:

  1. onFulfilled, onRejected 回调函数执行后返回值或者 Error 作为参数传递给下个 onFulfilled, onRejected
  2. then 执行后仍然是一个 promise 对象
// 示例
console.log('start')
new Promise(resolve => {
    resolve(1)
})
.then(res => res + 1)
.then(res => { 
    console.log("resolve(1) ~ then:return 1+1 ~ then: res", res) 
})
​
new Promise(resolve => {
    resolve(2)
})
.then(res => { throw new Error(res + 1) })
.then(res => { console.log(res) }, err => { 
  console.log("resolve(2) ~ then:throw Err 2+1 ~ then: err", err) 
})
​
new Promise((resolve, reject) => {
    reject(3)
})
.then(() => { }, err => err + 1)
.then(res => { 
    console.log("reject(3) ~ then:return 3+1 ~ then: res", res) 
})
​
new Promise((resolve, reject) => {
    reject(4)
})
.then(() => { },err => { throw new Error(err+1) })
.then(res => { console.log(res) }, err => { 
    console.log("reject(4) ~ then:throw Err 4+1 ~ then: err", err) 
})
console.log('end')
​
// start
// end
// resolve(1) ~ then:return 1+1 ~ then: res  2
// resolve(2) ~ then:throw Err 2+1 ~ then: err  Error: 3
// reject(3) ~ then:return 3+1 ~ then: res  4
// reject(4) ~ then:throw Err 4+1 ~ then: err   Error: 5
复制代码

实现思路:

  1. then 新建一个 promise,并返回
  2. push 到 resolvedQueue/rejectedQueue 的函数包括两步,执行 onFulfilled/onRejected 和 resolve /reject。

new Promise(resolve=>resolve(1)).then(res=>res+1).then(res=>console.log(res)) 为例说明实现过程

  1. pending状态:执行同步代码

    • new Promise 执行: resolve=>resolve(1) 执行
    • resolve(1)执行:需要执行的代码封装成函数 fn 加入到微任务中,fn 函数功能包括:状态修改为 fulfilled ,PromiseResult 值修改,执行 resolvedQueue 队列中的函数
    • then 执行: 创建 promise,添加函数队列数组 resolvedQueue 中,该函数的作用包括执行 onFulfilled/onRejected 和 resolve /reject(参数为onFulfilled/onRejected的返回值)
class MPromise {
    static PENDINGSTATUS = 'pending'
    static FULFILLESSTATUS = 'fulfilled'
    static REJECTEDSTATUS = 'rejected'
    constructor(executor) {
        this.PromiseState = MPromise.PENDINGSTATUS;
        this.PromiseResult = null;
        // 存放then 函数中需要执行的 onFulfilled, onRejected 回调函数
        this.resolvedQueue = [];
        this.rejectedQueue = [];
        // resolve 和 reject 执行时 this 的值为 window,需要绑定 this
        executor(this.resolve.bind(this), this.reject.bind(this));
    }
    resolve(res) {
        // +++ 以下代码有修改 
        if (this.PromiseState === MPromise.PENDINGSTATUS) {
            // 通过if 判断状态,实现无法再次修改 promise 的状态
            // 异步执行 resolvedQueue 队列中保存的 onFulfilled 函数
            // 开启微队列
            resultHandlerAsync(() => {
                this.PromiseResult = res;
                this.PromiseState = MPromise.FULFILLESSTATUS;
                if (this.resolvedQueue.length) {
                    const cb = this.resolvedQueue.shift();
                    cb(res)
                }
            })
        }
        // +++
    }
    reject(err) {
        // +++ 以下代码有修改 
        if (this.PromiseState === MPromise.PENDINGSTATUS) {
            // 异步执行 rejectedQueue 队列中保存的 onRejected 函数
            // 开启微队列
            resultHandlerAsync(() => {
                this.PromiseResult = err;
                this.PromiseState = MPromise.REJECTEDSTATUS;
                if (this.rejectedQueue.length) {
                    const cb = this.rejectedQueue.shift();
                    cb(err)
                }
            })
        }
        // +++
    }
    then(onFulfilled, onRejected) {
        // then 函数用来注册回调函数,将要执行的 onFulfilled, onRejected 回调函数加入到队列中
        // +++ 以下代码有修改 
        return new MPromise((resolve, reject) => {
            if (this.PromiseState === MPromise.PENDINGSTATUS) {
                // 改写目的:实现 onFulfilled 返回值,均会传递给下一次的 then 中 onFulfilled的参数
                this.resolvedQueue.push((res) => {
                    try {
                        const result = onFulfilled(res);
                        resolve(result);
                    } catch (err) {
                        reject(err)
                    }
                });
                this.rejectedQueue.push((err) => {
                    try {
                        const result = onRejected(err);
                        resolve(result);
                    } catch (err) {
                        reject(err)
                    }
                });
            }
        })
        // +++
    }
}
​
function resultHandlerAsync(cb) {
    // console.log('async')
    // 此函数会开启一个微任务,cb 放入到微任务中执行
    const observer = new MutationObserver(cb);
    observer.observe(document.body, { attributes: true });
    document.body.className = `${Math.random()}`;
}
​
console.log('start')
new MPromise(resolve => {
    resolve(1)
})
.then(res => res + 1)
.then(res => { 
    console.log("resolve(1) ~ then:return 1+1 ~ then: res", res) 
})
​
new MPromise(resolve => {
    resolve(2)
})
.then(res => { throw new Error(res + 1) })
.then(res => { console.log(res) }, err => { 
  console.log("resolve(2) ~ then:throw Err 2+1 ~ then: err", err) 
})
​
new MPromise((resolve, reject) => {
    reject(3)
})
.then(() => { }, err => err + 1)
.then(res => { 
    console.log("reject(3) ~ then:return 3+1 ~ then: res", res) 
})
​
new MPromise((resolve, reject) => {
    reject(4)
})
.then(() => { },err => { throw new Error(err+1) })
.then(res => { console.log(res) }, err => { 
    console.log("reject(4) ~ then:throw Err 4+1 ~ then: err", err) 
})
console.log('end')
// start
// end
// resolve(1) ~ then:return 1+1 ~ then: res  2
// resolve(2) ~ then:throw Err 2+1 ~ then: err  Error: 3
// reject(3) ~ then:return 3+1 ~ then: res  4
// reject(4) ~ then:throw Err 4+1 ~ then: err   Error: 5
复制代码

then 的参数非函数

// 示例
new Promise((resolve, reject) => {
    resolve(1)
}).then().then(res => { console.log("resolve(1) ~ undefined ~ then: res", res) })

new Promise((resolve, reject) => {
    reject(2)
}).then().then(undefined, err => { console.log("reject(2) ~ undefined ~ then: err", err) })

// resolve(1) ~ undefined ~ then: res 1
// reject(2) ~ undefined ~ then: err 2
复制代码

实现思路:

判断传入的参数是否为函数,如果是函数不做任何处理;如果不是函数,创建一个函数,该函数功能是直接返回resolve 改变的值或者抛出错误

then(onFulfilled, onRejected) {
    // +++ 以下代码为新增
    onFulfilled = (typeof onFulfilled === 'function') ? onFulfilled : res => res;
    onRejected = (typeof onRejected === 'function') ? onRejected : err => { throw err };
    // +++
    return new MPromise(...)
}
                        
new MPromise((resolve, reject) => {
    resolve(1)
}).then().then(res => { console.log("resolve(1) ~ undefined ~ then: res", res) })
​
new MPromise((resolve, reject) => {
    reject(2)
}).then().then(undefined, err => { console.log("reject(2) ~ undefined ~ then: err", err) })
​
// resolve(1) ~ undefined ~ then: res 1
// reject(2) ~ undefined ~ then: err 2
复制代码

Promise.prototype.catch 和 Promise.prototype.finally 的实现

catch 方法返回一个Promise ,并且处理拒绝的情况。

finally方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数

// 示例
new Promise((resolve, reject) => {
    reject(1)
})
.catch(err => { 
    console.log("reject(1) ~ then: err", err) 
})
​
new Promise((resolve, reject) => {
    reject(2)
})
.catch()
.then(() => { }, err => { 
    console.log("reject(2) ~ catch:undefined ~ then: err", err) 
})
​
new Promise((resolve, reject) => {
    reject(3)
})
.catch(err => err + 1)
.finally((value) => { 
    console.log("reject(3) ~ catch: err=>err+1 ~ finally:return 22", value); 
    return 22;
})
.then(res => { 
    console.log("reject(3) ~ catch: err=>err+1 ~ finally:return 22 ~ then: err", res)
})
// reject(1) ~ then: err   1
// reject(2) ~ catch:undefined ~ then: err    2
// reject(3) ~ catch: err=>err+1 ~ finally:return 22   undefined
// reject(3) ~ catch: err=>err+1 ~ finally:return 22 ~ then:err   4
复制代码

实现:

catch 方法相当于 then(undefined,onRejected)

finally 方法:异步执行传递的回调参数,同时将上一个 then 的结果传递到下一个

catch(onRejected) {
    return this.then(undefined,onRejected)
}
finally(cb){
    return new MPromise((resolve,reject)=>{
        if (this.PromiseState === MPromise.PENDINGSTATUS) {
            this.resolvedQueue.push((res) => {
                try {
                    cb()
                    resolve(res);
                } catch (err) {
                    reject(err)
                }
            });
            this.rejectedQueue.push((err) => {
                try {
                    cb();
                    resolve(err);
                } catch (err) {
                    reject(err)
                }
            });
        }
    })
}
​
new MPromise((resolve, reject) => {
    reject(1)
})
.catch(err => { 
    console.log("reject(1) ~ then: err", err) 
})
​
new MPromise((resolve, reject) => {
    reject(2)
})
.catch()
.then(() => { }, err => { 
    console.log("reject(2) ~ catch:undefined ~ then: err", err) 
})
​
new MPromise((resolve, reject) => {
    reject(3)
})
.catch(err => err + 1)
.finally((value) => { 
    console.log("reject(3) ~ catch: err=>err+1 ~ finally:return 22", value); 
    return 22;
})
.then(res => { 
    console.log("reject(3) ~ catch: err=>err+1 ~ finally:return 22 ~ then: err", res)
})
// reject(1) ~ then: err   1
// reject(2) ~ catch:undefined ~ then: err    2
// reject(3) ~ catch: err=>err+1 ~ finally:return 22   undefined
// reject(3) ~ catch: err=>err+1 ~ finally:return 22 ~ then:err   4
复制代码

Promise.resolve 和 Promise.reject 实现

Promise.resolve 方法返回一个以给定值解析后的 Promise 对象

Promise.reject 方法返回一个带有拒绝原因的 Promise 对象

实现方式

static resolve(res) {
    return new MPromise(resolve => resolve(res))
}
static reject(res) {
    return new MPromise((resolve, reject) => reject(res))
}
复制代码

Promise.all 和 Promise.race 实现

Promise.all() 方法接收一个 promise 的 可迭代类型(Array,Map,Set),并且只返回一个 Promise 对象。返回值为所有 resolve 的结果,如果出现任何一个 reject 的回调执行,则会立即抛出错误。

Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。

// 示例
const p1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 500, 'one');
});
​
const p2 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'two');
});
​
const p3 = new Promise((resolve, reject) => {
    setTimeout(reject, 300, 'three');
});
​
Promise.race([p1, p2]).then((value) => {
    console.log('Promise.race', value);
});
​
Promise.all([p1, p2, p3]).then((value) => {
    console.log('Promise.all ~ then:res', value);
}).catch(err=>{console.log('Promise.all ~ catch:err', err)});
​
Promise.all([p1, p2]).then((value) => {
    console.log('Promise.all', value);
});
// Promise.race  two
// Promise.all ~ catch:err three
// Promise.all   ['one', 'two']
复制代码
static race(promiseList) {
    return new MPromise((resolve, reject) => {
        promiseList.forEach(p => p.then(res => resolve(res), err => reject(err)))
    })
}
static all(promiseList) {
    return new MPromise((resolve, reject) => {
        let promiseArr = [];
        promiseList.forEach(p => {
            p.then(res => {
                promiseArr.push(res)
            }, err => {
                throw new Error(err);
                reject(err);
            })
        })
        resolve(promiseArr);
    })
}
复制代码

完整代码

class MPromise {
    static PENDINGSTATUS = 'pending'
    static FULFILLESSTATUS = 'fulfilled'
    static REJECTEDSTATUS = 'rejected'
    constructor(executor) {
        this.PromiseState = MPromise.PENDINGSTATUS;
        this.PromiseResult = null;
        // 存放then 函数中需要执行的 onFulfilled, onRejected 回调函数
        this.resolvedQueue = [];
        this.rejectedQueue = [];
        // resolve 和 reject 执行时 this 的值为 window,需要绑定 this
        executor(this.resolve.bind(this), this.reject.bind(this));
    }
    resolve(res) {
        // console.log('resolve')
        if (this.PromiseState === MPromise.PENDINGSTATUS) {
            // 通过if 判断状态,实现无法再次修改 promise 的状态
            // 异步执行 resolvedQueue 队列中保存的 onFulfilled 函数
            // 开启微队列
            resultHandlerAsync(() => {
                this.PromiseResult = res;
                this.PromiseState = MPromise.FULFILLESSTATUS;
                if (this.resolvedQueue.length) {
                    const cb = this.resolvedQueue.shift();
                    cb(res)
                }
            })
        }
    }
    reject(err) {
        if (this.PromiseState === MPromise.PENDINGSTATUS) {
            // 异步执行 rejectedQueue 队列中保存的 onRejected 函数
            // 开启微队列
            resultHandlerAsync(() => {
                this.PromiseResult = err;
                this.PromiseState = MPromise.REJECTEDSTATUS;
                if (this.rejectedQueue.length) {
                    const cb = this.rejectedQueue.shift();
                    cb(err)
                }
            })
        }
    }
    then(onFulfilled, onRejected) {
        // then 函数用来注册回调函数,将要执行的 onFulfilled, onRejected 回调函数加入到队列中
        onFulfilled = (typeof onFulfilled === 'function') ? onFulfilled : res => res;
        onRejected = (typeof onRejected === 'function') ? onRejected : err => { throw err };
        return new MPromise((resolve, reject) => {
            if (this.PromiseState === MPromise.PENDINGSTATUS) {
                // 改写目的:实现 onFulfilled 返回值,均会传递给下一次的 then 中 onFulfilled的参数
                this.resolvedQueue.push((res) => {
                    try {
                        const result = onFulfilled(res);
                        resolve(result);
                    } catch (err) {
                        reject(err)
                    }

                });
                this.rejectedQueue.push((err) => {
                    try {
                        const result = onRejected(err);
                        resolve(result);
                    } catch (err) {
                        reject(err)
                    }
                });
            }
        })
    }
    catch(onRejected) {
        return this.then(undefined, onRejected)
    }
    finally(cb) {
        return new MPromise((resolve, reject) => {
            if (this.PromiseState === MPromise.PENDINGSTATUS) {
                // 改写目的:实现 onFulfilled 返回值,均会传递给下一次的 then 中 onFulfilled的参数
                this.resolvedQueue.push((res) => {
                    try {
                        cb()
                        resolve(res);
                    } catch (err) {
                        reject(err)
                    }
                });
                this.rejectedQueue.push((err) => {
                    try {
                        cb();
                        resolve(err);
                    } catch (err) {
                        reject(err)
                    }
                });
            }
        })
    }
    static resolve(res) {
        return new MPromise(resolve => resolve(res))
    }
    static reject(res) {
        return new MPromise((resolve, reject) => reject(res))
    }
    static race(promiseList) {
        return new MPromise((resolve, reject) => {
            promiseList.forEach(p => p.then(res => resolve(res), err => reject(err)))
        })
    }
    static all(promiseList) {
        return new MPromise((resolve, reject) => {
            let promiseArr = [];
            promiseList.forEach(p => {
                p.then(res => {
                    promiseArr.push(res)
                }, err => {
                    throw new Error(err);
                    reject(err);
                })
            })
            resolve(promiseArr);
        })
    }
}

function resultHandlerAsync(cb) {
    // 此函数会开启一个微任务,cb 放入到微任务中执行
    const observer = new MutationObserver(cb);
    observer.observe(document.body, { attributes: true });
    document.body.className = `${Math.random()}`;
}
复制代码

Guess you like

Origin juejin.im/post/7076459957805121566