关于javascript:Promise源码实现

6次阅读

共计 6536 个字符,预计需要花费 17 分钟才能阅读完成。

Promise

一、promise 的简略应用

new Promise((resolve, reject) => {resolve("ok")
}).then(data => {console.log(data) //OK
}, error => {console.log(error)
})
// 简化下
let promise = new Promise(executor)
promise.then(onFulfilled, onRejected)

须要留神的是

  • executor是一个会被立刻执行的回调函数, 该函数带有两个参数,resolve reject
  • 如果 executor 中调用了 resolve(value) , 那么这个value 则会被传给onFulfilled, 如第一个例子中console.log(data) 输入为ok
  • 如果 executor 中调用了 reject(value) , 那么这个value 则会被传给 onRejected,作为onRejected 的实参
  • 还有一点须要留神的是,promise 是带有状态的,开始默认为 pending, 当调用 resolve 后,状态变更为 fulFilled, 当调用reject 后,状态变更为 rejected。当状态从pending 变更为 fulFilled / reject 后,状态不可再扭转

二、Promise 的高级实现

让咱们持续带着第一个用例 来做个 promise 的高级实现

new Promise((resolve, reject) => {resolve("ok")
}).then(data => {console.log(data) //OK
}, error => {console.log(error)
})

// 咱们带着例子逐行实现
// let executor = (resolve, reject) => {resolve("ok") }
// new Promise(executor)
class Promise {constructor(executor){
        this.status = "pending" // 状态默认为期待态
        //executor = (resolve, reject) => {resolve("ok") }
        // 传入的 executor 是一个带有两个参数的函数,
        // 并且参数 resolve 和 reject 都是可调用的函数
        // 所以咱们应该先申明这两个函数 而后当成实参传入 executor
        const resolve = (value) => { }
        const reject = (error) => { }
        executor(resolve,reject)
    }
    
}
// let executor = (resolve, reject) => {resolve("ok") }
// new Promise(executor)
class Promise {constructor(executor){
        this.status = "penging"
        this.resValue = null
        this.rejValue = null
        // executor = (resolve, reject) => {resolve("ok") }
        const resolve = (value) => {// 如 resolve("ok") 中传入的 "ok" 
            // 须要在前面代码的 then 的 onFulilled 中拿, 故须要存储这个 value 
            this.resValue = value
            // 并且调用 resolve 后,状态更改为 fulfilled
            if(this.status === "pending"){this.status = "fulfilled"}
        }
        const reject = (error) => {
            this.rejValue = error
            if(this.status === "pending"){this.status = "rejected"}
        }
        executor(resolve,reject)
    }
    
}
// let promise = new Promise(executor)
// promise.then(onFulfilled, onRejected)
// 能够得出 promise 须要一个 then 办法
class Promise {constructor(executor){// 如上...}
    then(onFulfilled, onRejected){
        // 调用 then 办法的时候, 要判断是以后状态是胜利还是失败
        if(this.status === "fulfilled"){
            // 如果以后是胜利态
            onFulfilled(this.value)
        }
        if(this.status === "rejected"){
            // 如果以后是失败态
            onRejected(this.error)
        }
    }
}

这样算是根本实现了 promise 的高级性能, 然而当 new promise(executor) 传入的 executor 为异步函数的时候,就会呈现问题。如下:

new Promise((resolve,reject)=>{setTimeout(()=>{resolve("ok") 
    },0)
}).then(data => {console.log(data) // 不会输入 ok
})
// 其起因是: 当 executor 为异步函数传入 new Promise` 时
// 尽管立刻调用了 executor, 然而其为异步函数, 会被推入微工作, 不会马上执行
// 所以上面这个 resolve 不会马上执行,会先执行宏工作的 then 办法
// 所以在执行 then 办法的时候,promise 的状态依然为 pending
class Promise {constructor(executor){// executor = setTimeout(()=>{resolve("ok")},0)
        const resolve = (value) => {
            // ** 2. 后执行
            this.value = value
            if(status === "pending"){this.status = "fulfilled"}
        }
        // ...
        executor(resolve,reject)
    }
    then(onFulfilled, onRejected){
        // ** 1. 先执行
        if(this.status === "fulfilled"){onFulfilled(this.value)
        }
        // ...
    } 
}

Promise 的高级实现之异步改良

当初的问题是, 在传入异步函数的时候,咱们执行到 then 办法的时候, 状态还是为 pending, 所以无奈执行到onFulfilled。咱们又须要在executor 中调用了resolve 后执行 onFulfilled。所以很天然的想到了应用公布订阅模式来解决。即在 then 中判断到以后为期待态时 (那executor 肯定是异步函数), 将 onFulfilledonRejected存起来, 在 executor 中执行到 resolve 后 执行onFulfilled。上面是代码实现:

class Promise {constructor(executor){
        this.status = "pending"
        //onFulfilled 汇合
        this.onFulfilledCallbacks = [ ]
        //onRejected 汇合
        this.onRejectedCallbacks = [ ]
        
        const resolve = (value) => {
            this.resValue = value
            if(status === "pending"){
                this.status = "fulfilled"
                // 公布
                this.onFulfilledCallbacks.forEach(callback => {callback(this.value)
                })
            }
        }
        const reject = (error) => {
            this.rejValue = error
            if(status === "pending"){
                this.status = "rejected"
                this.onRejectedCallbacks.forEach(callback => {callback(this.error)
                })
            }
        }
        executor(resolve,reject)
    }
    then(onFulfilled, onRejected){
        // 同步代码不变, 减少异步状况代码
        if(this.status === "fulfilled"){onFulfilled(this.value)
        }
        if(this.status === "rejected"){onRejected(this.error)
        }
        // 新增代码
        if(this.status === "pending"){
            // 曾经到 then 了,status 的状态还没有扭转。// 阐明 executor 中为异步函数
            // 订阅
            this.onFulfilledCallbacks.push((data)=>{
                // 切片
                onFulfilled(data)
            })
            this.onRejectedCallbacks.push((error)=>{onRejected(error)
            })
        }
        
    }
}

以上就是 promise 的高级实现,promise 的外围在于他们链式调用。咱们在下一章具体介绍

三、理解 promise 的链式调用

    new Promise((resolve,reject) => {resolve("hello")
    }).then(data => {console.log(data) //hello
        return "world"
    }).then(data => {console.log(data) //world
    })

如果在 then 中 return 一个简略值 (非promise), 那么将在下一个 then 中的onFulfilled 取到这个值。

    new Promise((resolve,reject) => {resolve("hello")
    }).then(data => {throw new Error()
    }).then(data => {console.log(data) 
    },error => {console.log(error) // Error
    })

如果在 then 中抛出异样, 那么将会在下一个 then 的 onRejected 拿到这个异样。

    let promise1 = new Promise((resolve,reject) => {resolve("hello")
    }).then(data => {return data})
    
    console.log(promise1) // Promise{<fulfilled>: "hello"}
    // 能够看得出来: 在 then 办法中, 会返回一个 promise 对象
    // 因为 promise 的状态不可二次扭转, 所以返回的应该是一个新的 promise 对象

四、测试案例剖析

在实现 promise 的链式调用前, 首先要有个测试案例:

let promise1 = new Promise((resolve, reject) => {setTimeout(() => {resolve("the message is")
    }, 0);
})
let promise2 = promise1.then(data => {let interPromise = new Promise((resolve,reject) => {setTimeout(() => {resolve(data + "that today is a happy day")
        }, 0);
    })
    return interPromise
}, null)

我感觉有必要先剖析下这个 promise2

  • 1. 首先咱们晓得这个 promise1.then() 肯定是返回一个新的promise, 而且是一个带着实现或完结态的promise
  • 2. 所以在 then 的外部生成一个 promise, 并且在外部实现了这个promiseresolve(data), 而且这个data 来之外部的 interPromiseresolve()
  • 3. 再看下这个 interPromise, 他要想把外部的resolve(data + "that today is a happy day") 里的数据传给下层 thenpromise, 那么只能是隐性的调用 interPromisethen, 并且在这个 then 中, 调用下层 promiseresolve
  • 这是 promise 中的最难点, 如果没看懂, 能够多看几遍, 糊涂的话能够先看上面的代码实现,再回过头来看这段剖析
let promise3 = promise2.then(data => {console.log(data) // expect: the message is that today is a happy day
})

六、promise 的链式调用

该案例为了不便浏览和了解,就实现了最难的性能, 并且省略了异样捕捉等内容。

// constructor 不变,只对 then 办法进行了批改
class Promise {constructor(executor) {
        this.status = "pending"
        this.resValue = null
        this.rejValue = null
        this.onfulfilledCallbacks = []
        this.onrejectedCallbacks = []
        const resolve = (value) => {
            this.resValue = value
            if (this.status === "pending") {
                this.status = "fulfilled"
                this.onfulfilledCallbacks.forEach(callback => {callback(this.resValue)
                })
            }
        }
        const reject = (error) => {
            this.rejValue = value
            if (this.status === "pending") {
                this.status = "rejected"
                this.onrejectedCallbacks.forEach(callback => {callback(this.rejValue)
                })
            }
        }
        executor(resolve, reject)
    }
    then(onFulfilled, onRejected) {// onFulfilled = data => new Promise(...)
        //then 办法返回 promise2
        const promise2 = new Promise((resolve2,reject2) => {if (this.status === "pending") {
                //async 
                // 这里须要一个实现一个异步
                // 因为在 resolvePromise 中须要 实现初始化的 promise2
                setTimeout(()=>{
                    this.onfulfilledCallbacks.push(data => {
                        // 代入案例来看
                        // 这个 x = interPromise
                        let x = onFulfilled(data)
                        // 而后判断这个 x 是否是一个 promise
                        resolvePromise(x, resolve2, reject2)
                    })
                    
                    this.onrejectedCallbacks.push(error => {
                        // 类比下面进行批改,这里不做批改
                        onRejected(error)
                    }) 
                },0)
            }
            // 上面状况和下面同理,我不做批改
            if (this.status === "fulfilled") {onFulfilled(this.resValue)
            }
            if (this.status === "rejected") {onRejected(this.rejValue)
            }
            
        })
        return promise2
    }
}

function resolvePromise(x, resolve2, reject2){
    // 源码中有许多判断的异样捕捉,这里就实现最外围的代码
    if((typeof x === "object" && typeof x !== "null")|| typeof x === "function"){
        // x is a object or function
        let then = x.then
        if(typeof then === "function"){
            // 在这里调用 interPromise 的 then 
            // 并且调用下层 promise 的 resolve
            then.call(x,data => resolve2(data),null)
            // x is a promise
            // for example: x = new promise((resolve,reject) => {resolve("ok")})
        }
    }
}
正文完
 0