Promise:手写Promise,原理分析

源码地址:https://gitee.com/lagou-19-web-paid/practice/tree/master/promise

1- Promise 对象的基础模型 (同步,分析执行流程)

  1. Promise 是一个类,类接收的是一个构造函数,在执行类的时候这个构造函数也会同步执行。
  2. 构造函数在同步执行的时候,会传递俩个回调函数,分别是成功回调[resolve]、失败回调[reject]。
  • 成功回调:回调函数内接收一个参数,可以是一个普通值,也可以是一个 Promise 对象。此阶段暂时只考虑普通值。
  • 失败回调:回调函数内接收一个参数,一般为失败原因
  1. Promise 中有三个状态,分别为 等待[pending]、成功[fulfilled]、失败[rejected]。状态仅支持 pending -> fulfilled 或 pending -> rejected,状态一旦确定就不支持修改了。
  2. then 方法会接收俩个参数,成功回调[successCallback]函数、失败回调[failCallback]函数。在 then 方法执行时,会依据Promise 的执行状态,执行成功回调或者失败回调。并在执行相对应的回调时,取出相对应的缓存状态值,作为参数传递至回调函数。
    
    // Promise 的三个状态
    const PENDING = 'pending' // 等待
    const FULFILLED = 'fulfilled' // 成功
    const REJECTED = 'rejected' // 失败
    
    /**
    *   模拟 原生Promise
    *   
    *   @class MyPromise
    *   @constructor excutor 构造函数,函数接收俩个回调函数,回调函数
    */
    class MyPromise {
        constructor( excutor ) {
            excutor(this.resolve, this.reject)
        }
        
        // 默认状态为 pending(等待)
        status = PENDING
        
        // 缓存状态值
        value = undefined // 成功状态 【参数】
        reason = undefined // 失败状态 【原因】


        /**
        *   成功回调
        *
        *   @see 函数使用箭头函数,可以使 this 指向于当前 MyPromise 对象
        */
        resolve = (value) => {
            // 状态一旦确定不支持更改,return 出函数
            if (this.status !== PENDING) return
            
            // 更改状态为 fulfilled(成功)
            this.status = FULFILLED
            
            // 缓存成功回调 传递的值
            this.value = value
        }
        
        /**
        * 失败回调
        */
        reject = (reason) => {
            // 状态一旦确定不支持更改,return 出函数
            if (this.status !== PENDING) return
            
            // 更改状态为 rejected(失败)
            this.status = REJECTED
            
            // 缓存失败回调 传递的原因
            this.reason = reason
        }
        
        /**
        *   then 方法
        *
        *   @params {function} successCallback[成功回调]
        *   @params {function} failCallback[失败回调]
        */
        then ( successCallback, failCallback ) {
            if (this.status === FULFILLED) successCallback(this.value)
            if (this.status === REJECTED) failCallback(this.reason)
        }
    }
    
    
    // 测试当前 MyPromise 
    
    let promiseTest = new MyPromise((resolve, reject) => {
        resolve('成功')
        // reject('失败')
    })
   // 执行 then 方法 
    promiseTest.then(value => {
        console.log(value)
    }, reason => {
        console.log(reason)
    })

2- Promise 对象的异步特性

  1. 异步特点就是不会阻塞代码执行,待异步结束后才会得到特定的值、特定的函数才会执行。
  2. 当执行 Promise 中的 then 方法时,Promise 对象的状态为 pending[等待状态时],就断定为异步状态。
  3. 断定为异步状态时,successCallback[成功回调]、failCallback[失败回调] 需要缓存在 Promise 对象中。
  4. 在构造函数内的异步方法执行完毕,调用 resolve[成功回调] 、reject[失败回调] 时,前置逻辑处理完毕后,最后执行外部调用 then 方法挂载至 Promise 对象中的 successCallbak[成功回调] 或 failCallback[失败回调]。
    
    // Promise 的三个状态
    const PENDING = 'pending' // 等待
    const FULFILLED = 'fulfilled' // 成功
    const REJECTED = 'rejected' // 失败
    
    /**
    *   模拟 原生Promise
    *   
    *   @class MyPromise
    *   @constructor excutor 构造函数,函数接收俩个回调函数,回调函数
    */
     resolve = (value) => {
         // 状态一旦确定不支持更改,return 出函数
         if (this.status !== PENDING) return

         // 更改状态为 fulfilled(成功)
         this.status = FULFILLED

         // 缓存成功回调 传递的值
         this.value = value

         // 执行成功回调
         this.successCallback && this.successCallback(this.value)
     }

     /**
     * 失败回调
     */
     reject = (reason) => {
         // 状态一旦确定不支持更改,return 出函数
         if (this.status !== PENDING) return

         // 更改状态为 rejected(失败)
         this.status = REJECTED

         // 缓存失败回调 传递的原因
         this.reason = reason

         // 执行失败回调
         this.failCallback && this.failCallback(this.reason)
     }
        
    /**
    *   then 方法
    *
    *   @params {function} successCallback[成功回调]
    *   @params {function} failCallback[失败回调]
    */
    then ( successCallback, failCallback ) {
        if (this.status === FULFILLED) successCallback(this.value)
        else if (this.status === REJECTED) failCallback(this.reason)
        else {
            // 缓存成功回调
            this.successCallback = successCallback
            // 缓存失败回调
            this.failCallback = failCallback
        }
    }
}


// 测试当前 MyPromise

let promiseTest = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('成功')
        // reject('失败')
    }, 2000)
})
promiseTest.then((value) => {
    console.log('成功回调:', value)
}, (reason) => {
    console.log('失败原因:', reason)
})


3- Promise 支持多次调用的特性实现

  1. 创建 Promise 方法是可以被多次调用的,在调用后每个 then 方法都应该被正确执行。
  2. 改造缓存回调函数的容器为数组,每次执行 then 方法后,successCallback[成功回调]、failCallback[失败回调] 都应进入对应的缓存栈。
  3. 在构造函数内调用 resolve[成功回调] 、reject[失败回调] 时,循环执行缓存的回调函数,并在回调函数内传入当前 Promise 的成功数据,或失败原因。

// Promise 的三个状态
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected' // 失败
/**
 *   模拟 原生Promise
 *  
 *   @class MyPromise
 *   @constructor excutor 构造函数,函数接收俩个回调函数,回调函数
 */
class MyPromise {
    constructor(excutor) {
        excutor(this.resolve, this.reject)
    }
    // 默认状态为 pending(等待)
    status = PENDING
    
    // 缓存状态值
    value = undefined // 成功状态 【参数】
    reason = undefined // 失败状态 【原因】
    // 缓存回调函数
    
    successCallback = [] // 成功回调
    failCallback = [] // 失败回调
    /**
     *   成功回调
     *
     *   @see 函数使用箭头函数,可以使 this 指向于当前 MyPromise 对象
     */
    resolve = (value) => {
        // 状态一旦确定不支持更改,return 出函数
        if (this.status !== PENDING) return
        
        // 更改状态为 fulfilled(成功)
        this.status = FULFILLED
        
        // 缓存成功回调 传递的值
        this.value = value
        
        // 执行成功回调
        while (this.successCallback.length) this.successCallback.shift()(this.value)
    }
    /**
     * 失败回调
     */
    reject = (reason) => {
        // 状态一旦确定不支持更改,return 出函数
        if (this.status !== PENDING) return
        
        // 更改状态为 rejected(失败)
        this.status = REJECTED
        
        // 缓存失败回调 传递的原因
        this.reason = reason
        
        // 执行失败回调
        while (this.failCallback.length) this.failCallback.shift()(this.reason)
    }
    /**
     *   then 方法
     *
     *   @params {function} successCallback[成功回调]
     *   @params {function} failCallback[失败回调]
     */
    then(successCallback, failCallback) {
        if (this.status === FULFILLED) successCallback(this.value)
        else if (this.status === REJECTED) failCallback(this.reason)
        else {
            // 缓存成功回调
            this.successCallback.push(successCallback)
            // 缓存失败回调
            this.failCallback.push(failCallback)
        }
    }
}


// 测试当前 MyPromise

let promiseTest = (status, num) => {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            if (status) resolve(`成功:${num}`)
            else reject(`失败:${num}`)
        }, 2000)
    })
}
promiseTest(true, 1).then((value) => {
    console.log('成功回调:', value)
}, (reason) => {
    console.log('失败原因:', reason)
})
promiseTest(false, 2).then((value) => {
    console.log('成功回调:', value)
}, (reason) => {
    console.log('失败原因:', reason)
})
promiseTest(true, 3).then((value) => {
    console.log('成功回调:', value)
}, (reason) => {
    console.log('失败原因:', reason)
})

4- Promise 链式调用的特性实现

  1. 链式调用过程中,then 方法的 successCallback[成功回调]、failCallback[失败回调],是可选项。如果为空,则直接返回上一个 Promise 对象的返回值。
  2. Promise 对象是支持链式调用的,在执行 then 方法的时候,最终会返回一个新的 Promise 对象。
  3. 返回的对象,不支持返回当前调用的 Promise 对象。
  4. 返回的对象如果是对象,则获取 promise 的返回值,依据返回值调用 resolve、reject。
  5. 返回值是普通值则,调用 resolve 方法。

// Promise 的三个状态
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected' // 失败

/**
 *   模拟 原生Promise
 *  
 *   @class MyPromise
 *   @constructor excutor 构造函数,函数接收俩个回调函数,回调函数
 */
class MyPromise {
    constructor(excutor) {
        try {
            excutor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }
    }
    
    // 默认状态为 pending(等待)
    status = PENDING
    
    // 缓存状态值
    value = undefined // 成功状态 【参数】
    reason = undefined // 失败状态 【原因】
    
    // 缓存回调函数
    successCallback = [] // 成功回调
    failCallback = [] // 失败回调
    
    /**
     *   成功回调
     *
     *   @see 函数使用箭头函数,可以使 this 指向于当前 MyPromise 对象
     */
    resolve = (value) => {
        // 状态一旦确定不支持更改,return 出函数
        if (this.status !== PENDING) return
        // 更改状态为 fulfilled(成功)
        this.status = FULFILLED
        // 缓存成功回调 传递的值
        this.value = value
        // 执行成功回调
        while (this.successCallback.length) this.successCallback.shift()()
    }
    
    /**
     * 失败回调
     */
    reject = (reason) => {
        // 状态一旦确定不支持更改,return 出函数
        if (this.status !== PENDING) return
        // 更改状态为 rejected(失败)
        this.status = REJECTED
        // 缓存失败回调 传递的原因
        this.reason = reason
        // 执行失败回调
        while (this.failCallback.length) this.failCallback.shift()()
    }
    
    /**
     *   then 方法
     *
     *   @params {function} successCallback[成功回调]
     *   @params {function} failCallback[失败回调]
     */
    then(successCallback, failCallback) {
        // 回调参数可以为空
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => { throw reason }
        
        const promiseNext = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                // 当前代码块改变为异步状态,获取到 promiseNext 对象
                setTimeout(() => {
                    try {
                        // 获取到回调结果
                        let successNext = successCallback(this.value)
                        // 执行返回逻辑
                        resolvePromise(promiseNext, successNext, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        // 获取到回调结果
                        let failNext = failCallback(this.reason)
                        // 执行返回逻辑
                        resolvePromise(promiseNext, failNext, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else {
                // 缓存成功回调
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            // 获取到回调结果
                            let successNext = successCallback(this.value)
                            // 执行返回逻辑
                            resolvePromise(promiseNext, successNext, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
                // 缓存失败回调
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            // 获取到回调结果
                            let failNext = failCallback(this.reason)
                            // 执行返回逻辑
                            resolvePromise(promiseNext, failNext, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
            }
        })
        // 链式调用,返回新的Promise
        return promiseNext
    }
}

// 链式调用处理回调函数
function resolvePromise(promise, next, resolve, reject) {
    // 禁止返回当前 Promise
    if (promise === next) return reject(new TypeError('Chaining cycle detected for promise #'))
    // 判断当前返值状态
    if (next instanceof MyPromise) next.then(resolve, reject) // 如果 返回值为 Promise 对象,则获取到返回值,并调用 resolve、reject 方法传递
    else resolve(next) // 如果是普通值,则直接调用 resolve 方法
}


// 测试当前 MyPromise

let promiseTest = (status, num) => {
    return new MyPromise((resolve, reject) => {
        // setTimeout(() => {
            if (status) resolve(`成功:${num}`)
            else reject(`失败:${num}`)
        // }, 2000)
    })
}

// 链式调用
promiseTest(true, 1).then((value) => {
    console.log('成功回调:', value)
    throw Error(value.replace(/成功/, '失败').replace(/[0-9]/g, 2))
}, (reason) => {
    console.log('失败原因:', reason)
}).then((value) => {
    console.log('成功回调:', value)
    return value.replace(/[0-9]/g, 3)
}, (reason) => {
    console.log('失败原因:', reason)
    return (reason && reason.message || '失败:3').replace(/失败/, '失败 -> 成功').replace(/[0-9]/g, '2 -> 3')
}).then((value) => {
    console.log('成功回调:', value)
    return value.replace(/[0-9]/g, 4)
}, (reason) => {
    console.log('失败原因:', reason)
})

// 参数可选
promiseTest(true, 100).then().then().then((value) => console.log('value', value))
promiseTest(false, -100).then().then().then((value) => console.log(value), (reason) => console.log('reason', reason))

5- Promise 中的 all、resolve、finally、catch 方法

  • Promise 中的 all 方法

    1. all 方法是一 Promise 的静态方法,可以直接调用。
    2. 接收的参数为数组,数组中可以有普通值、同步方法、异步方法。
    3. 调用 all 方法后,会依次按顺序执行形参中的数组包含的值或方法。每个值或执行方法后,获取到的结果应按形参中的顺序缓存。
    4. all 方法最终的返回值是一个 Promise 对象。如果形参中的每个方法都得以正确执行,没有异常则调用 Promise 对象中的 resolve 方法,把最终结果缓存至返回的 Promise 对象中。如果有异常则把异常的原因,则调用 Promise 对象中的 reject 方法,缓存失败原因。
    5. 执行 then 方法就可以获取到,all 顺利完整执行的结果,或某一个状态失败的原因。
  • Promise 中的 resolve 方法

    1. resolve 方法也是一个 Promise 的静态方法,可以直接调用。
    2. resolve 方法接收一个参数,这个参数可以是普通值,也可以是异步方法。
    3. 如果接收到的值是普通值,则包装为 Promise 方法后,返回这个 Promise 方法。
    4. 如果接收到的值是异步方法,则直接返回这个方法。
  • Promise 中的 finally 方法

    1. finally 方法在 Promise 对象执行后,无论结果是 fulfilled 或 rejected,都会被执行。
    2. finally 返回值应为一个 Promise 对象,并且继承当前 Promise 对象的状态。
    3. finally 对象由于无法知道 Promise 的状态,所以回调函数函数不接收任何参数,仅用于无论 Promise 对象何种状态,都要执行的情况。
  • Promise 中的 catch 方法

    1. catch 方法会捕获 Promise 的失败状态。
    2. catch 方法内部为调用 then 方法,第一个参数,成功状态为空。

6- 完整的 Promise 对象


// Promise 的三个状态
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected' // 失败

/**
 *   模拟 原生Promise
 *  
 *   @class MyPromise
 *   @constructor excutor 构造函数,函数接收俩个回调函数,回调函数
 */
class MyPromise {
    constructor(excutor) {
        try {
            excutor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }
    }
    
    // 默认状态为 pending(等待)
    status = PENDING
    
    // 缓存状态值
    value = undefined // 成功状态 【参数】
    reason = undefined // 失败状态 【原因】
    
    // 缓存回调函数
    successCallback = [] // 成功回调
    failCallback = [] // 失败回调
    
    /**
     *   成功回调
     *
     *   @see 函数使用箭头函数,可以使 this 指向于当前 MyPromise 对象
     */
    resolve = (value) => {
        // 状态一旦确定不支持更改,return 出函数
        if (this.status !== PENDING) return
        // 更改状态为 fulfilled(成功)
        this.status = FULFILLED
        // 缓存成功回调 传递的值
        this.value = value
        // 执行成功回调
        while (this.successCallback.length) this.successCallback.shift()()
    }
    
    /**
     * 失败回调
     */
    reject = (reason) => {
        // 状态一旦确定不支持更改,return 出函数
        if (this.status !== PENDING) return
        // 更改状态为 rejected(失败)
        this.status = REJECTED
        // 缓存失败回调 传递的原因
        this.reason = reason
        // 执行失败回调
        while (this.failCallback.length) this.failCallback.shift()()
    }
    
    /**
     *   then 方法
     *
     *   @params {function} successCallback[成功回调]
     *   @params {function} failCallback[失败回调]
     */
    then(successCallback, failCallback) {
        // 回调参数可以为空
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => { throw reason }
        
        const promiseNext = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                // 当前代码块改变为异步状态,获取到 promiseNext 对象
                setTimeout(() => {
                    try {
                        // 获取到回调结果
                        let successNext = successCallback(this.value)
                        // 执行返回逻辑
                        resolvePromise(promiseNext, successNext, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        // 获取到回调结果
                        let failNext = failCallback(this.reason)
                        // 执行返回逻辑
                        resolvePromise(promiseNext, failNext, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else {
                // 缓存成功回调
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            // 获取到回调结果
                            let successNext = successCallback(this.value)
                            // 执行返回逻辑
                            resolvePromise(promiseNext, successNext, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
                // 缓存失败回调
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            // 获取到回调结果
                            let failNext = failCallback(this.reason)
                            // 执行返回逻辑
                            resolvePromise(promiseNext, failNext, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
            }
        })
        // 链式调用,返回新的Promise
        return promiseNext
    }
    
    /**
    *   Promise 对象的 finally 方法
    */
    finally(callback) {
        // 调用   then 方法,获取 Promise 的状态,并返回
        return this.then(
                // 传递成功值,并把 回调函数包装为 Promise 对象 返回
                (value) => MyPromise.resolve(callback()).then(() => value),
                // 传递失败原因,并把 回调函数包装为 Promise 对象 返回
                (reason) => MyPromise.resolve(callback().then(() => { throw reason })
            ))
    }
    
    /**
    *   Promise 对象的 then 方法
    */
    catch(callback) {
        return this.then(undefined, callback)
    }
    
    
    /**
    *   Promise 对象的 all 方法
    */
    static all(array) {
        // 缓存最终结果
        let result = []
        // 缓存结果的
        let count = 0
        // 返回 Promise 对象
        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                // 按下标缓存最终值
                result[key] = value
                
                // 缓存值的次数
                count++
                
                // 缓存值的次数,等于 all 形参的长度,则代表所有方法或值都缓存至结果
                if (count === array.length) resolve(result)
            }
            
            // 循环依次执行
            for (let i = 0; i < array.length; i++) {
                // 获取当前执行
                let current = array[i]
                // 异步方法处理
                if (current instanceof MyPromise) {
                    current.then(value => addData(i, value), reason => resolve(reason))
                } else { // 普通值处理
                    addData(i, current)
                }
            }
        })
    }
    
    /**
    *   Promise 对象的 resolve 方法
    */
    static resolve(value) {
        if (value instanceof MyPromise) return value // Promise 对象则直接返回
        else return new MyPromise(resolve => resolve(value)) // 普通值,则包装为异步方法
    }
}

// 链式调用处理回调函数
function resolvePromise(promise, next, resolve, reject) {
    // 禁止返回当前 Promise
    if (promise === next) return reject(new TypeError('Chaining cycle detected for promise #'))
    // 判断当前返值状态
    if (next instanceof MyPromise) next.then(resolve, reject) // 如果 返回值为 Promise 对象,则获取到返回值,并调用 resolve、reject 方法传递
    else resolve(next) // 如果是普通值,则直接调用 resolve 方法
}

你可能感兴趣的:(JS基础,javascript)