手写Promise及其问题

169 阅读2分钟

基础功能

        class Bromise{
            static PENDING = '待定'
            static FULFILLED = '成功'
            static REJECTED = '失败'
            constructor(func){
                this.status = Bromise.PENDING
                this.result = null
                func(this.resolve,this.reject)
            }

            resolve(result){
                if(this.status === Bromise.PENDING){
                    this.status = Bromise.FULFILLED
                    this.result = result
                }
            }

            reject(result){
                if(this.status === Bromise.PENDING){
                    this.status = Bromise.REJECTED
                    this.result = result
                }
            }
        }
        
        let bromise = new Bromise((resolve,reject)=>{
            resolve('成功')
        })

问题:报错Uncaught TypeError: Cannot read properties of undefined (reading 'status')
原因:类中所有定义的方法,在浏览器运行时候全部都加上了 user strict !
所以第8行的this指向的其实是undefined。

绑定this

解决方法:bind绑定。

        class Bromise{
            static PENDING = '待定'
            static FULFILLED = '成功'
            static REJECTED = '失败'
            constructor(func){
                this.status = Bromise.PENDING
                this.result = null
                func(this.resolve.bind(this),this.reject.bind(this))
            }

            resolve(result){
                if(this.status === Bromise.PENDING){
                    this.status = Bromise.FULFILLED
                    this.result = result
                }
            }

            reject(result){
                if(this.status === Bromise.PENDING){
                    this.status = Bromise.REJECTED
                    this.result = result
                }
            }
        }
        
        let bromise = new Bromise((resolve,reject)=>{
            resolve('成功')
        })

实现then方法

        class Bromise{
            static PENDING = '待定'
            static FULFILLED = '成功'
            static REJECTED = '失败'
            constructor(func){
                this.status = Bromise.PENDING
                this.result = null
                func(this.resolve.bind(this),this.reject.bind(this))
            }

            resolve(result){
                if(this.status === Bromise.PENDING){
                    this.status = Bromise.FULFILLED
                    this.result = result
                }
            }

            reject(result){
                if(this.status === Bromise.PENDING){
                    this.status = Bromise.REJECTED
                    this.result = result
                }
            }

            then(onFULFILLED,onREJECTED){
                if(this.status === Bromise.FULFILLED){
                    onFULFILLED(this.result)
                }
                if(this.status === Bromise.REJECTED){
                    onREJECTED(this.result)
                }
            }
        }

        let bromise = new Bromise((resolve,reject)=>{
            resolve('成功')
        })
        bromise.then(
            result => {console.log(result)},
            error  => {console.log(error)}
        )

错误处理

问题一:then方法传入的若不是函数,就不能正常运行
问题二:若抛出异常,则不能正确接收
解决:

        class Bromise{
            static PENDING = '待定'
            static FULFILLED = '成功'
            static REJECTED = '失败'
            constructor(func){
                this.status = Bromise.PENDING
                this.result = null
                try{
                    func(this.resolve.bind(this),this.reject.bind(this))
                }catch(err){
                    this.reject(error)
                }
                
            }

            resolve(result){
                if(this.status === Bromise.PENDING){
                    this.status = Bromise.FULFILLED
                    this.result = result
                }
            }

            reject(result){
                if(this.status === Bromise.PENDING){
                    this.status = Bromise.REJECTED
                    this.result = result
                }
            }

            then(onFULFILLED,onREJECTED){
                onFULFILLED = typeof onFULFILLED === 'function' ? onFULFILLED : ()=>{}
                onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : ()=>{}
                if(this.status === Bromise.FULFILLED){
                    onFULFILLED(this.result)
                }
                if(this.status === Bromise.REJECTED){
                    onREJECTED(this.result)
                }
            }
        }

        let bromise = new Bromise((resolve,reject)=>{
            resolve('成功')
        })
        bromise.then(
            result =>{console.log(result)},
            error =>{console.log(error)}
        )

实现异步

问题:若对resolve或reject进行异步调用,则调用then方法的时候状态处于pending,会导致进不去resolve和reject,所以需要进行异步的实现。
resolveCallbacks和rejectCallbacks的作用:当处于pending状态时,将回调函数添加进去这两个数组,等到下个事件循环的时候执行。

        class Bromise {
            static PENDING = '待定'
            static FULFILLED = '成功'
            static REJECTED = '失败'
            constructor(func) {
                this.status = Bromise.PENDING
                this.result = null
                this.resolveCallbacks = []
                this.rejectCallbacks = []
                try {
                    func(this.resolve.bind(this), this.reject.bind(this))
                } catch (err) {
                    this.reject(error)
                }

            }

            resolve(result) {
                setTimeout(() => {
                    if(this.status === Bromise.PENDING){
                        this.result = result
                        this.status = Bromise.FULFILLED
                        this.resolveCallbacks.forEach(callback => callback(result))
                    }
                })
            }

            reject(result) {
                setTimeout(() => {
                    if(this.status === Bromise.PENDING){
                        this.result = result
                        this.status = Bromise.REJECTED
                        this.rejectCallbacks.forEach(callback => callback(result))
                    }
                })
            }

            then(onFULFILLED, onREJECTED) {
                onFULFILLED = typeof onFULFILLED === 'function' ? onFULFILLED : () => { }
                onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }
                if(this.status === Bromise.PENDING){
                    this.resolveCallbacks.push(onFULFILLED)
                    this.rejectCallbacks.push(onREJECTED)
                }
                if (this.status === Bromise.FULFILLED) {
                    setTimeout(() => {
                        onFULFILLED(this.result)
                    })
                }
                if (this.status === Bromise.REJECTED) {
                    setTimeout(() => {
                        onREJECTED(this.result)
                    })
                }
            }
        }

then方法返回Promise(链式调用)

        class Bromise {
            static PENDING = '待定'
            static FULFILLED = '成功'
            static REJECTED = '失败'
            constructor(func) {
                this.status = Bromise.PENDING
                this.result = null
                this.resolveCallbacks = []
                this.rejectCallbacks = []
                try {
                    func(this.resolve.bind(this), this.reject.bind(this))
                } catch (err) {
                    this.reject(error)
                }

            }

            resolve(result) {
                setTimeout(() => {
                    if (this.status === Bromise.PENDING) {
                        this.result = result
                        this.status = Bromise.FULFILLED
                        this.resolveCallbacks.forEach(callback => callback(result))
                    }
                })
            }

            reject(result) {
                setTimeout(() => {
                    if (this.status === Bromise.PENDING) {
                        this.result = result
                        this.status = Bromise.REJECTED
                        this.rejectCallbacks.forEach(callback => callback(result))
                    }
                })
            }

            then(onFULFILLED, onREJECTED) {
                return new Bromise((resolve, reject) => {
                    onFULFILLED = typeof onFULFILLED === 'function' ? onFULFILLED : () => { }
                    onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }
                    if (this.status === Bromise.PENDING) {
                        this.resolveCallbacks.push(onFULFILLED)
                        this.rejectCallbacks.push(onREJECTED)
                    }
                    if (this.status === Bromise.FULFILLED) {
                        setTimeout(() => {
                            onFULFILLED(this.result)
                        })
                    }
                    if (this.status === Bromise.REJECTED) {
                        setTimeout(() => {
                            onREJECTED(this.result)
                        })
                    }
                })
            }
        }

问题

这个实现实际上有很大的问题,Promise.resolve和Promise.reject本来是微任务,但是这里的代码搞成了宏任务。例如,对于下面的代码:

        setTimeout(() => {
            console.log(3)
        })
        let promise = new Promise((resolve, reject) => {
            resolve(1)
        })
        promise.then(result => { console.log(result) })
        console.log(2)

结果理应是:2 1 3
我的代码的结果:2 3 1
我在网上查阅了很多博客,基本上结果都是1 2 3或者是2 3 1,都和本来的正确结果相去甚远。
可以说:只要代码里面有setTimeout,都不是正确的Promise,Promise自己本来是不应该产生任何宏任务的。
那么如何实现真正的Promise呢?
这就需要后续的深入研究了。