手写promise原理

77 阅读5分钟

promise基础用法

let p1 = new Promise((resolve, reject) => {
    resolve('成功')
    reject('失败')
})
console.log('p1', p1)     // 成功

let p2 = new Promise((resolve, reject) => {
    reject('失败')
    resolve('成功')        
})
console.log('p2', p2)     // 失败

let p3 = new Promise((resolve, reject) => {
    throw('报错')
})
console.log('p3', p3)             // 失败

image.png 从这段代码的执行,我们可以获取到几个知识点

  1. 成功会执行resolve函数,失败会执行reject函数
  2. 状态不可逆,状态一旦变化,后面再更改状态是无效的
  3. 执行throw等同于执行reject

实现resolve和reject

class myPromise {
    promiseResult = "";
    constructor(excutor) {
        excutor(this.resolve, this.reject)
    }

    resolve = (value) => {
        this.promiseResult = value
        this.promiseStatus = 'fulfilled'
        console.log('resolve', value)
    }

    reject = (reason) => {
        this.promiseResult = reason;
        this.promiseStatus = 'rejected'
        console.log('reject', reason)
    }
}



let p1 = new myPromise((resolve, reject) => {
    resolve('成功')
})
console.log('p1', p1)

image.png

状态不可逆

let p1 = new myPromise((resolve, reject) => {
    resolve('成功')
    reject('失败')
})
console.log('p1', p1)

image.png

我们会发现成功和失败都执行,然后最后的状态变成了rejected,显然违背了promise状态的不可逆,按照正常逻辑,此处应该返回的状态应该是成功,那我们怎么改呢,我们知道,promise的初始状态是pending,只有在pending状态才可以变成fulfilled或rejected,一旦状态变成fulfilled或者rejected,那么就不在执行成功或失败的函数了,改造后的代码

class myPromise {
    promiseResult = "";
    promiseStatus = 'pending';
    constructor(excutor) {
        excutor(this.resolve, this.reject)
    }

    resolve = (value) => {
        if (this.promiseStatus !== 'pending') return; //状态不可逆
        this.promiseResult = value
        this.promiseStatus = 'fulfilled'
        console.log('resolve', value)
    }

    reject = (reason) => {
        if (this.promiseStatus !== 'pending') return; //状态不可逆
        this.promiseResult = reason;
        this.promiseStatus = 'rejected'
        console.log('reject', reason)
    }
}



let p1 = new myPromise((resolve, reject) => {
    resolve('成功')
    reject('失败')
})
console.log('p1', p1)

image.png

throw

throw等同于执行reject,那我们用try/catch改造下

    constructor(excutor) {
        try{
            excutor(this.resolve, this.reject)
        }catch(e){
            this.reject(e)
        }
    }
    
   const test3 = new MyPromise((resolve, reject) => {
        throw('失败')
    })
  console.log(test3) // MyPromise { PromiseState: 'rejected', PromiseResult: '失败' }

then

// 马上输出 ”成功“
const p1 = new Promise((resolve, reject) => {
    resolve('成功')
}).then(res => console.log(res), err => console.log(err))

// 1秒后输出 ”失败“
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('失败')
    }, 1000)
}).then(res => console.log(res), err => console.log(err))

// 链式调用 输出 200
const p3 = new Promise((resolve, reject) => {
    resolve(100)
}).then(res => 2 * res, err => console.log(err))
  .then(res => console.log(res), err => console.log(err))

上面的代码我们可以得出几个结论

  • then接收两个回调,一个成功的回调一个失败的回调
  • 当状态为fulfilled执行成功的回调,状态为rejected执行失败的回调
  • 当resolve或reject在定时器内,先执行定时器再执行then
  • then返回的也是promise,可以链式调用

实现then

 then = (onFulfilled, onRejected) => {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
        if (this.promiseStatus === 'fulfilled') {
            onFulfilled()
        } else if (this.promiseStatus === 'rejected') {
            onRejected()
        }
    }
 // 马上输出  成功
const p1 = new Promise((resolve, reject) => {
    resolve('成功')
}).then(res => console.log(res), err => console.log(err))

定时器

class myPromise {
    promiseResult = "";
    promiseStatus = 'pending';
    onFulfilledArr = [];   // 存放成功的回调
    onRejectedArr = [];     // 存放失败的回调
    constructor(excutor) {
        try {
            excutor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }

    }

    resolve = (value) => {
        if (this.promiseStatus !== 'pending') return; //状态不可逆
        this.promiseResult = value
        this.promiseStatus = 'fulfilled'
        // 执行保存的成功的回调
        if(this.onFulfilledArr.length){
            this.onFulfilledArr.forEach(fn=>fn(this.promiseResult))
        }
    }

    reject = (reason) => {
        if (this.promiseStatus !== 'pending') return; //状态不可逆
        this.promiseResult = reason;
        this.promiseStatus = 'rejected'
        // 执行保存的失败的回调
        if(this.onRejectedArr.length){
            this.onRejectedArr.forEach(fn=>fn(this.promiseResult))
        }
    }
    then = (onFulfilled, onRejected) => {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
        if (this.promiseStatus === 'fulfilled') {
            onFulfilled()
        } else if (this.promiseStatus === 'rejected') {
            onRejected()
        } else {
            // pending状态,还未执行resolve或reject时吧成功和失败的回调分别存起来
            this.onFulfilledArr.push(onFulfilled);
            this.onRejectedArr.push(onRejected)
        }
    }

}
// 马上输出 ”成功“
const p1 = new Promise((resolve, reject) => {
    resolve('成功')
}).then(res => console.log(res), err => console.log(err))

// 1秒后输出 ”失败“
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('失败')
    }, 1000)
}).then(res => console.log(res), err => console.log(err))

链式调用

    then = (onFulfilled, onRejected) => {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
        // 既然是链式调用,那么then的返回值一定是一个promise
        const result = new myPromise((resolve, reject) => {

            // 传入成功或失败的函数名
            const handler = (cb) => {
                try {
                    // 拿到成功或失败的返回值做一些处理
                    const res = cb(this.promiseResult);
                    if (res === result) {
                        throw new Error('不能返回自身')
                    }
                    if (res instanceof myPromise) {
                        // 如果返回值是promise
                        // 如果返回值是promise对象,返回值为成功,新promise就是成功,返回值为失败,新promise就是失败
                        // 那怎么知道是成功还是失败,只有then回调知道
                        res.then(resolve, reject)
                    } else {
                        resolve(res)
                    }
                } catch (err) {
                    reject(err)
                }

            };

            if (this.promiseStatus === 'fulfilled') {
                handler(onFulfilled)
            } else if (this.promiseStatus === 'rejected') {
                handler(onRejected)
            } else {
                this.onFulfilledArr.push(onFulfilled);
                this.onRejectedArr.push(onRejected)
            }
        })
        return result
    }

微任务

const p1 = new myPromise((resolve, reject) => {
    resolve('成功')
}).then(res => console.log(res), err => console.log(err))

console.log(99)

正常结果应该是先输出99,再输出成功,因为then是微任务,会等到当前宏任务执行完才执行then函数里的微任务,这时我们只需要把then函数内的handler处理函数改成定时器就行了,因为定时器是宏任务,会等到前一个宏任务及其下面的微任务执行完再执行下一个宏任务,上代码

  then = (onFulfilled, onRejected) => {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
        // 既然是链式调用,那么then的返回值一定是一个promise
        let result

        result = new myPromise((resolve, reject) => {
            // 传入成功或失败的函数名
            const handler = (cb) => {
                setTimeout(() => {
                    try {
                        // 拿到成功或失败的返回值做一些处理
                        const res = cb(this.promiseResult);
                        if (res === result) {
                            throw new Error('不能返回自身')
                        }
                        if (res instanceof myPromise) {
                            // 如果返回值是promise
                            // 如果返回值是promise对象,返回值为成功,新promise就是成功,返回值为失败,新promise就是失败
                            // 那怎么知道是成功还是失败,只有then回调知道
                            res.then(resolve, reject)
                        } else {
                            resolve(res)
                        }
                    } catch (err) {
                        reject(err)
                    }
                })
            };

            if (this.promiseStatus === 'fulfilled') {
                handler(onFulfilled)
            } else if (this.promiseStatus === 'rejected') {
                handler(onRejected)
            } else {
                this.onFulfilledArr.push(onFulfilled);
                this.onRejectedArr.push(onRejected)
            }
        })
        return result
    }

其他方法

all

所有的promise都成功,所有成功的回调放入一个数组返回,如果有一个promise失败,就会返回这个失败的回调


    static all = (promises) => {
        let result = []
        let count = 0;
        return new myPromise((resolve, reject) => {
            promises.forEach((fn, index) => {
                if (fn instanceof myPromise) {
                    fn.then = res => {
                        result[index] = res;
                        count++
                    }
                } else {
                    result[index] = res;
                    count++
                }
            })
            if (count === promises.length) {
                resolve(result)
            }
        })
    }

any

    // 只要有任意一个promise成功就返回这个成功的回调,如果所有的promise都失败,就返回失败
    static any = (promises) => {
        return new myPromise((resolve, reject) => {
            let count = 0;
            promises.forEach(promise => {
                // if (promise instanceof myPromise) {
                promise.then((res) => {
                    resolve(res);
                }, err => {
                    count++;
                    if (count === promises.length) {
                        reject('all rejected')
                    }
                })
                // }else{
                //     resolve(promise)
                // }
            })
        })

race

// 哪个promise最先返回结果,就直接返回这个结果,无论成功失败 static race = (promises) => { return new myPromise((resolve, reject) => { promises.forEach(promise => { if (promise instanceof myPromise) { promise.then(res => { resolve(res) }, err => { reject(err) }) } else { resolve(promise) } }) }) }

allsettled

    // 返回所有的promise结果,无论是成功还是失败
    static allsettled = (promises) => {

        return new myPromise((resolve, reject) => {
            const result = [];
            let count = 0;
            const handler = (status, value, index) => {
                result[index] = { status, value };
                count++;
                if (count === promises.length) {
                    resolve(result)
                }
            }
            promises.forEach((promise,index) => {
                if (promise instanceof myPromise) {
                    promise.then(res => handler('fulfilled', res, index), err => handler('rejected', err, index))
                } else {
                    handler('fulfilled', promise, index)
                }
            })
        })
    }