八股文不用背-手写promise

100 阅读4分钟

使用方式

new Promise((resolve, reject) => {
    console.log(1)
    resolve()
}).then(res => {
    console.log(2)
},err=>{})

输出结果是1、2 从这个例子看上去我们要实现的目标有

  1. Promise是一个对象,构造函数接受一个函数
  2. promise对象有一个属性then

构造函数

promise内部需要两个方法提供给外部使用

  • resolve代表成功完成,之后执行then的成功回调
  • reject代表失败,之后执行then的失败回调
class q{
    constructor(fn){
        this.init()
        // 当然如果这个函数执行失败了,自然得执行reject
        try {
            fn(this.resolve,this.reject)
        } catch(err){
            this.reject()
        }
    }
    init(){
        this.resolve = ()=>{
            // 执行成功函数
        }
        this.reject = ()=>{
            // 执行失败函数
        }
    }
}

then方法

promise需要一个then方法才能在new promise之后调用then,该方法接收两个函数 => 成功回调和失败回调,分别在resolve、reject之后执行,但是走到then的时候可能resolve/reject了,也可能没有

情况一

走到then时,前面已经resolve/reject了,我们文章开头的例子就是这样,在new promise时,执行了构造函数,此时已经执行了resolve,然后走到了then方法时就可以直接执行成功回调了。当然我们得设置一个状态才能做到。

class q{
    constructor(fn){
       this.init()
       fn(this.resolve,this.reject)
    }
    init(){
        // 初始等待状态
        this.state = 'pending'
        this.result = ''
        this.resolve = (data)=>{
            if(this.state !== 'pending') return
            // 执行成功函数
            this.state = 'successed'
            this.result = data
        }
        this.reject = ()=>{
            if(this.state !== 'pending') return
            // 执行失败函数
            this.state = 'failed'
            this.result = data
        }
        this.then = (successCb,failCb)=>{
            // 判断此刻的状态,决定执行那个
            if(this.state === 'successed') successCb(this.result)
            else if(this.state === 'failed') failCb(this.result)
        }
    }
}

情况二

走到then时,前面没有resolve,reject,也就是说此刻的状态的等待中,那then里面该怎么写呢?
我们可以先将then的两个回调保存起来,然后在resolve/reject方法里调用就好啦!

class q{
    constructor(fn){
       this.init()
       fn(this.resolve,this.reject)
    }
    init(){
        // 初始等待状态
        this.state = 'pending'
        this.result = ''
        // 存放成功失败回调
        this.callBackArr = []
        this.resolve = (data)=>{
            if(this.state !== 'pending') return
            // 执行成功函数
            this.state = 'successed'
            this.result = data
            // 执行成功回调
            this.callBackArr.length && this.callBackArr.shift().successCb(this.result)
        }
        this.reject = ()=>{
            if(this.state !== 'pending') return
            // 执行失败函数
            this.state = 'failed'
            this.result = data
            // 执行失败回调
            this.callBackArr.length && this.callBackArr.shift().failCb(this.result)
        }
        this.then = (successCb,failCb)=>{
            // 判断此刻的状态,决定执行那个
            if(this.state === 'successed') successCb(this.result)
            else if(this.state === 'failed') failCb(this.result)
            else {
                // 如果此刻状态是等待中,就将两个回调存放在callBackCb
                this.callBackCb.push({successCb:successCb,failCb:failCb})
            }
        }
    }
}
// 使用
new q((resolve, reject) => {
    console.log(1)
    resolve()
}).then(res => {
    console.log(2)
},err=>{})

这已经实现了最初的例子了,然后来看看更复杂的例子

复杂例子

new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log(1)
        resolve()
    }, 1000);
}).then(res => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(2)
            resolve()
        }, 1000);
    })
},err=>{}).then(res => {
    console.log(3)
},err=>{})

new promise传入的函数里是异步的,这个我们已经通过状态变化实现了。但是第一个then里面的返回的是promise,且then可以链式调用这两个点没实现。

链式调用

简单,那就then函数返回的是promise对象即可了

    this.then = (successCb,failCb)=>{
        return new q((resolve,reject)=>{
            // 判断此刻的状态,决定执行那个
            if(this.state === 'successed'){
                successCb(this.result)
                resolve()
            } else if(this.state === 'failed'){
                failCb(this.result)
                reject()
            } else {
                // 如果此刻状态是等待中,就将两个回调存放在callBackCb
                this.callBackCb.push({successCb:()=>{
                    successCb()
                    resolve()
                },failCb:()=>{
                    failCb()
                    reject()
                }})
            }
        })
    }

then返回了一个promise

如果then返回了一个promise对象的话,那么得等这个promise对象resolve/reject之后才执行下一个then函数,其实就相当于then内部不需要返回了promise(假)

    this.then = (successCb,failCb)=>{
        return new q((resolve,reject)=>{
            // 判断此刻的状态,决定执行那个
            if(this.state === 'successed'){
                successCb(this.result)
                resolve()
            } else if(this.state === 'failed'){
                failCb(this.result)
                reject()
            } else {
                // 如果此刻状态是等待中,就将两个回调存放在callBackCb
                this.callBackCb.push({successCb:()=>{
                    let result = successCb()
                    if(result instanceof q){
                        result.then(res=>{
                            resolve(this.result)
                        },err=>{
                            reject(this.result)
                        })
                    } else resolve(this.result)
                },failCb:()=>{
                    let result = failCb()
                    if(result instanceof q){
                        result.then(res=>{
                            resolve(this.result)
                        },err=>{
                            reject(this.result)
                        })
                    } else reject(this.result)
                }})
            }
        })
    }

全部代码

class q {
    constructor(exect) {
        this.init()
        try {
            exect(this.resolve, this.reject)
        } catch (err) {
            this.reject(err)
        }
    }
    init() {
        this.state = 'pending'
        this.result = ''
        this.thenArr = []
        this.initResolve()
        this.initReject()
        this.initThen()
    }
    initResolve() {
        this.resolve = (data) => {
            if (this.state !== 'pending') return
            this.state = 'success'
            this.result = data
            this.thenArr.length && this.thenArr.shift().successCb(this.result)
        }
    }
    initReject() {
        this.reject = (err) => {
            if (this.state !== 'pending') return
            this.state = 'fail'
            this.result = err
            this.thenArr.length && this.thenArr.shift().failCb(this.result)
        }
    }
    initThen() {
        this.then = (successCb,failCb) => {
            successCb = typeof successCb === 'funciton' ? successCb: val=>val
            failCb = typeof failCb === 'funciton' ? failCb: val=>val
            return new q((resolve,reject)=>{
                // 判断此刻的状态,决定执行那个
                if(this.state === 'successed'){
                    successCb(this.result)
                    resolve()
                } else if(this.state === 'failed'){
                    failCb(this.result)
                    reject()
                } else {
                    // 如果此刻状态是等待中,就将两个回调存放在callBackCb
                    this.callBackCb.push({successCb:()=>{
                        let result = successCb()
                        if(result instanceof q){
                            result.then(res=>{
                                resolve(this.result)
                            },err=>{
                                reject(this.result)
                            })
                        } else resolve(this.result)
                    },failCb:()=>{
                        let result = failCb()
                        if(result instanceof q){
                            result.then(res=>{
                                resolve(this.result)
                            },err=>{
                                reject(this.result)
                            })
                        } else reject(this.result)
                    }})
                }
            })
        }
    }
}
new q((resolve, reject) => {
    setTimeout(() => {
        console.log('1')
        resolve()
    }, 1000);
}).then(res => {
    return new q((resolve, reject) => {
        setTimeout(() => {
            console.log(2)
            resolve()
        }, 1000);
    })
}).then(res => {
    console.log(3)
})

Promise.all就是用一个promise执行promiseList的所有元素,然后所有promise执行成功的结果数组,或者返回错误的一个promise的结果

promise.race就是用一个promise执行所有promiselist,返回最快执行完的promise的结果

promise.allSettled就是用一个promise执行所有的promiseList,返回结果数组

promise.any(与all相反),用一个promise执行所有promiseList,返回成功的一个promise,或者promise都错误,则报错