渐进理解Promise源码实现

387 阅读9分钟

promise代码实现要点

1、Promise是一个类,在执行的时候需要传入可执行的函数,这个函数会立即执行,并且执行之后Promise的状态会从pending转变成fufilled(成功)或rejected(失败),并且这一过程是不可逆的。

实现的第一步大致如下:

const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
    // 实例化的时候会立即执行
    constructor(executor) {
        // 利用try catch来处理构造器可能发生的错误       
   try {            
     executor(this.resolve, this.reject)       
   } catch (e) {  
          this.reject(e);    
      }   
 }
    status = PENDING
    // 执行成功后返回的值
    value = undefined
    // 执行失败后返回的值
    reason = undefined
    resolve = (value) => {
        // 如果状态不是等待状态,则不能往下执行
        if(this.status !== PENDING) return 
        this.status = FULFILLED
        this.value = value
        this.successCallback && this.successCallback(this.value)
    }
    reject = (error) => {
        if(this.status !== PENDING) return 
        this.status = REJECTED
        this.reason = error
        this.failCallback && this.failCallback(this.reason)
    }
    then (successcallback,failcallback) {
        if(this.status === FULFILLED){
            successcallback(this.value)
        }
        else if(this.status === REJECTED) {
            failcallback(this.reason)
        }
      
    }
}

module.exports = MyPromise;

在另一个文件中调用这个类:

const MyPromise = require('./myPromise')
function p1() {
    return new MyPromise((resolve,reject) => {
            resolve('success')
    
}
let promise1 = p1()

此时promise1已经拿到p1内部的执行结果了,如果想要拿到执行结果的数据,可通过使用then方法,then方法根据状态去调用成功回调或者失败回调,我们在类中加入此方法:

then (successcallback,failcallback) {
        if(this.status === FULFILLED){
            successcallback(this.value)
        }
        else if(this.status === REJECTED) {
            failcallback(this.reason)
        }
    }

promise1.then((data)=>{
    console.log(data);
},error => {
    console.log(error);
})

至此,一个无异步操作代码初步实现

在函数中加入异步操作

function p1() {
    return new MyPromise((resolve,reject) => {
        setTimeout(() => {
            resolve('success')
        }, 2000);
     
}
let promise1 = p1()
promise1.then(data => {
    
})

然后是对then、resolve、reject方法做修改:

   // 成功回调
    successCallback = undefined;
    // 失败回调
    failCallback = undefined;
    resolve = (value) => {
        // 如果状态不是等待状态,则不能往下执行
        if(this.status !== PENDING) return 
        this.status = FULFILLED
        this.value = value
        this.successCallback && this.successCallback(this.value)
    }
    reject = (error) => {
        if(this.status !== PENDING) return 
        this.status = REJECTED
        this.reason = error
        this.failCallback && this.failCallback(this.reason)
    }
    then (successcallback,failcallback) {
        if(this.status === FULFILLED){
            successcallback(this.value)
        }
        else if(this.status === REJECTED) {
            failcallback(this.reason)
        }
        // 状态为pendding时
        else {
	   // 保存回调函数
            this.successCallback = successcallback
            this.failCallback = failcallback
        }
    }

这样就初步实现异步操作了,但这仅仅是调用了一次then方法的情况,如果多次调用then方法的时候:

1、首先要把successCallback与failCallback定义为数组,这样它们就可以在状态为pendding时接收多个回调;

2、在resolve与reject两个函数中对这两个数组里边的回调函数进行调用

// 成功回调
 successCallback = [];
 // 失败回调
 failCallback = [];

 resolve = (value) => {
     // 如果状态不是等待状态,则不能往下执行
     if (this.status !== PENDING)
         return
         this.status = FULFILLED 
         this.value = value 
         while (this.successCallback.length) {
                 this.successCallback.shift()(value)
             }
 }

 reject = (error) => {
     if (this.status !== PENDING)
         return
         this.status = REJECTED
         this.reason = error 
	 while (this.failCallback.length) {
                 this.failCallback.shift()(error)
             }
 }

 then(successcallback, failcallback) {
     if (this.status === FULFILLED) {
         successcallback(this.value)
     } else if (this.status === REJECTED) {
         failcallback(this.reason)
     }
     // 状态为pendding时
     else {
         this.successCallback.push(successcallback)
         this.failCallback.push(failcallback)
     }
 }

链式使用then方法

我们在promise中链式使用then方法时,当前then执行的结果可以传递给下一个then方法中,而且这个执行的结果必须是一个promise对象

promise1.then(data => {
    return 1000;
}).then(data => {
    console.log(data) //这里将会打印上一个回调函数返回的结果
})

then方法中的修改:

then(successcallback, failcallback) {
    let promise2 = new MyPromise((resolve, reject) => {
        if (this.status === FULFILLED) {
            let res1 = successcallback(this.value);
            resolve(res1);
        } else if (this.status === REJECTED) {
            let err1 = failcallback(this.reason)reject(err1);
        }
        // 状态为pendding时
        else {
            this.successCallback.push(successcallback)
            this.failCallback.push(failcallback)
        }
    })
        return promise2;
}

但以上没有对res1的类型做判断,它可能会具备两种情况,普通值或者promise对象,

1、如果是普通值直接调用resolve

2、如果是promise对象,查看promise对象返回的结果,再根据promise对象返回的结果决定调用resolve 还是调用reject

以上两个判断步骤在状态成功或者失败时都要执行一遍

//声明一个函数去判断执行结果的类型
function resolvePromise(res, resolve, reject) {
    if (res instanceof MyPromise) {
        // promise 对象
        res.then(value => resolve(value), reason => reject(reason));
    } else { 
	// 普通值
        resolve(res);
    }
}
then(successcallback, failcallback) {
    let promise2 = new MyPromise((resolve, reject) => {
        if (this.status === FULFILLED) {
            let res1 = successcallback(this.value);
            resolvePromise(res1, resolve, reject)
        } else if (this.status === REJECTED) {
            let err1 = failcallback(this.reason)
            resolvePromise(err1, resolve, reject)
        } // 状态为pendding时
        else {
            this.successCallback.push(successcallback)
            this.failCallback.push(failcallback)
        }
    })
        return promise2;
}

测试代码中:

function p1() {
    return new MyPromise((resolve, reject) => {
        resolve('success')
    })
}
function p2() {
    return new MyPromise(function (resolve, reject) {
        resolve('p2')
    })
}
let promise1 = p1();
promise1.then((data) => {
    console.log(data); //success    
	return p2();
	}).then(value => {    
	console.log(value);//p2
	})

promise中当前执行执行的回调中是不能返回对象本身的,所以我们还要在then方法中加判断执行结果是否就是对象本身

then(successcallback, failcallback) {
     let promise2 = new MyPromise((resolve, reject) => {
         if (this.status === FULFILLED) {
             // 这里用异步是因为要将promise2传到另一个函数中,所以要等promise2实例化完毕
             setTimeout(() => {
                 let res1 = successcallback(this.value);
                 resolvePromise(promise2, res1, resolve, reject)
             }, 0);
         } else if (this.status === REJECTED) {
             let err1 = failcallback(this.reason)resolvePromise(err1, resolve, reject)
         } // 状态为pendding时
         else {
             this.successCallback.push(successcallback)this.failCallback.push(failcallback)
         }
     })
    return promise2;
 }
 function resolvePromise(promise2, res, resolve, reject) {
     if (promise2 === res) {
         return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
     }
     if (res instanceof MyPromise) {
         // promise 对象
         res.then(value => resolve(value), reason => reject(reason));
       
     } else {
         // 普通值
         resolve(res);
     }
 }

此时then方法中核心部分基本完成,但还未对错误状态进行捕获处理

then(successcallback, failcallback) {
    let promise2 = new MyPromise((resolve, reject) => {
        if (this.status === FULFILLED) {
            // 这里用异步是因为要将promise2传到另一个函数中,所以要等promise2实例化完毕
            setTimeout(() => {
                try {
                    let res1 = successcallback(this.value);
                    resolvePromise(promise2, res1, resolve, reject)
                } catch (e) {
                    // 将捕获到的错误传给下一个promise的reject方法
                    reject(e)
                }
            }, 0);
        } else if (this.status === REJECTED) {
            setTimeout(() => {
                try {
                    let err1 = failcallback(this.reason)
                        resolvePromise(promise2, err1, resolve, reject)
                } catch (e) {
                    reject(e)
                }
            }, 0);
        }
        // 状态为pendding时
        else { // 这里也要对回调函数的执行结果进行处理
            this.successCallback.push(() => {
                try {
                    let res = successcallback(this.value)
                        resolvePromise(promise2, res, resolve, reject)
                } catch (e) {
                    reject(e)
                }
            })
            this.failCallback.push(() => {
                try {
                    let err = failcallback(this.reason)
                        resolvePromise(promise2, err, resolve, reject)
                } catch (e) {
                    reject(e)
                }
            })
        }
    })
        return promise2;
}

then方法中的回调函数可作为可选参数

此外当一个promise对象多次链式调用then方法时,前边调用then方法中没有传递参数,最后一个then方法中的形参是可以拿到上一个回调函数(then)的返回值,也就是说then方法的参数是可选值;而在then方法中要对传入的两个回调函数进行判断,如果传入的函数为空则要做其他处理:

       //then方法中加入这两句代码去做判断 
      successcallback = successcallback ? successcallback : value => value;       
     failcallback = failcallback ? failcallback : error => { throw error }

测试代码中:

let promise1 = new MyPromise((resolve, reject) => {
    resolve('success')
    // reject("fail")});
    promise1.then().then().then(data => {
        console.log(25);
        console.log(data);
    }, err => {
        console.log(err);
    })

Promise.all的实现

all方法接收的是一个数组,这个数组里边可以包含普通值以及Promise的实例对象,在执行的时候等数组中所有的promise对象状态都变为fulfilled时,然后返回一个结果数组,但在执行的过程中如果有其中一个promise对象的状态变为失败状态,则会直接触发reject回调返回失败值

static all(array) {
    // 结果返回数组
    let result = []
    let count = array.length;
    return new MyPromise((resolve, reject) => {
        if (!Array.isArray(array)) {
            return reject(new Error("The args must be array type"))
        }
        function normalData(key, value) {
            result[key] = value
                count--;
            if (count == 0) {
                resolve(result)
            }
        }
        // for循环中存在异步操作,要等待异步操作执行完拿到结果才能进行下一步的操作
        for (let i = 0; i < array.length; i++) {
            const current = array[i];
            if (current instanceof MyPromise) {
                current.then(value => normalData(i, value), error => reject(error))
            } else {
                // 普通值
                normalData(i, array[i])
            }
        }
    })
}

测试代码中:

function p1() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('success')
        }, 2000);
    })
}
function p2() {
    return new MyPromise((resolve, reject) => {
        reject('p2')
    })
}
MyPromise.all([1, 2, p1(), p2(), 44]).then(res => {
    console.log(res);
}, err => {
    console.log("22" + err);
})

Promise.resolve的实现

resolve方法实现的思路比较简单,接收到传入的参数后先去判断它是否为promise对象,如果是则直接返回,否则将在方法内部实例化一个Promise对象,并且在这个新实例化的对象中传入一个执行器去调用resolve方法,并返回这个对象。

static resolve(value) {
    if (value instanceof MyPromise)
        return value else {
            return new MyPromise(resolve => resolve(value))
        }
}

测试代码中:

function p1() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {

            resolve('success')
        }, 2000);
    })
}

MyPromise.resolve(1000).then(res => {
    console.log(res);
})
MyPromise.resolve(p1()).then(res => {
    console.log(res);
})

Promise.finally的实现

finally方法的特点是无论当前的promise对象最终执行的结果是成功还是失败都会去执行此方法,并且能够链式调用then方法拿到当前Promise对象执行结果;

finally(callback) {        return this.then((value) => {            callback()            return value;        },(error) => {            callback()            throw error;        })    }

测试代码中:

function p2() {    return new MyPromise(function (resolve, reject) {        resolve('p2 success')    })}p2().finally(()=> {    console.log("回调");    }).then(res => {    console.log(res);})

这里代码是有个问题的,如果我们在finally里边的回调函数中返回一个promise对象,finally方法是需要等待这个promise对象执行完成,所以需要做:

1、判断回调函数返回的是普通值还是promise对象

2、无论是普通值(将其转换为promise对象)还是promise对象都要等待它执行完成,并且返回结果值

finally (callback) {
            return this.then((value) => {
                return MyPromise.resolve(callback()).then(value => value)

            }, (error) => {
                return MyPromise.resolve(callback()).then(error => {
                    throw error
                })

            })
        }

测试代码中:

function p1() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            // resolve('success')
            reject("fail p1")
        }, 2000);
    })
}
function p2() {
    return new MyPromise(function (resolve, reject) {
        // resolve('p2 success')
        reject("p2 fail")
    })
}
p2().finally(() => {
    console.log("回调");
    return p1()
}).then(res => {
    console.log(res);
}, err => {
    console.log(err);
})

catch方法

此方法用于处理当前的promise对象最终状态为失败的情况,也就是在then中是可以不传递失败的回调,然后失败的回调就会被catch所捕获

catch (failCallback) {
    return this.then(undefined, failCallback)
}

测试代码中:

function p2() {
    return new MyPromise((resolve, reject) => {
        resolve('p2 success')
        // reject("p2 fail")
    })
}
p2().catch(err => {
    console.log(err);
}).then(res => {
    console.log(res);
})

完整代码:

const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
    // 实例化的时候会立即执行
    constructor(executor) {
        // 利用try catch来处理构造器可能发生的错误
        try {
            executor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e);
        }
    }
    status = PENDING
        // 执行成功后返回的值
        value = undefined
        // 执行失败后返回的值
        reason = undefined
        // 成功回调
        successCallback = [];
    // 失败回调
    failCallback = [];
    resolve = (value) => {
        // 如果状态不是等待状态,则不能往下执行
        if (this.status !== PENDING)
            return
            this.status = FULFILLED
                this.value = value while (this.successCallback.length) {
                    this.successCallback.shift()()
                }
    }
    reject = (error) => {
        if (this.status !== PENDING)
            return
            this.status = REJECTED
                this.reason = error while (this.failCallback.length) {
                    this.failCallback.shift()(error)
                }
    }
    then(successcallback, failcallback) {

        successcallback = successcallback ? successcallback : value => value;
        failcallback = failcallback ? failcallback : error => {
            throw error
        }
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                // 这里用异步是因为要将promise2传到另一个函数中,所以要等promise2实例化完毕
                setTimeout(() => {
                    try {
                        let res1 = successcallback(this.value);
                        resolvePromise(promise2, res1, resolve, reject)
                    } catch (e) {
                        // 将捕获到的错误传给下一个promise的reject方法
                        reject(e)
                    }

                }, 0);
            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let err1 = failcallback(this.reason)
                            resolvePromise(promise2, err1, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }

                }, 0);

            }
            // 状态为pendding时
            else {
                // 这里也要对回调函数的执行结果进行处理
                this.successCallback.push(() => {
                    try {
                        let res = successcallback(this.value)
                            resolvePromise(promise2, res, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }

                })
                this.failCallback.push(() => {
                    try {
                        let err = failcallback(this.reason)
                            resolvePromise(promise2, err, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
            }
        })
            return promise2;
    }
    static all(array) {

        // 结果返回数组
        let result = []
        let count = array.length;
        return new MyPromise((resolve, reject) => {
            if (!Array.isArray(array)) {
                return reject(new Error("The args must be array type"))
            }
            function normalData(key, value) {
                result[key] = value
                    count--;
                if (count == 0) {
                    console.log("108" + " " + result);
                    resolve(result)
                }
            }
            // for循环中存在异步操作,要等待异步操作执行完拿到结果才能进行下一步的操作
            for (let i = 0; i < array.length; i++) {
                const current = array[i];
                if (current instanceof MyPromise) {
                    current.then(value => normalData(i, value), error => reject(error))
                } else {
                    // 普通值
                    normalData(i, array[i])
                }
            }

        })

    }
    static resolve(value) {
        if (value instanceof MyPromise)
            return value else {
                return new MyPromise(resolve => resolve(value))
            }
    }
    finally (callback) {
            return this.then((value) => {
                return MyPromise.resolve(callback()).then(value => value)

            }, (error) => {
                return MyPromise.resolve(callback()).then(error => {
                    throw error
                })

            })
        }
    catch (failCallback) {
        return this.then(undefined, failCallback)
    }
}

function resolvePromise(promise2, res, resolve, reject) {
    if (promise2 === res) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if (res instanceof MyPromise) {
        // promise 对象
        res.then(value => resolve(value), reason => reject(reason));
        //   res.then(resolve, reject);
    } else {
        // 普通值
        resolve(res);
    }
}
module.exports = MyPromise;