学习笔记:Promise核心实现原理

166 阅读7分钟

前言:该内容仅为本人的学习笔记,如果有出错的地方欢迎指正,感谢

Promise源码

1.核心实现原理

  • Promise就是一个类 在执行这个类的时候需要传递一个执行器进去,执行器会立即执行
  • Promise中由三个状态分别的fulfilled、、pending,一旦状态确定了就不可改变
  • resolve(fulfilled)和reject(rejected)函数式用来更改状态
  • then方法的内部做的事情就是判断状态,并调用对应函数,且这个给方法在原型对象上
  • then成功过回调由一个参数表示成功的值,失败有一个值表示失败后的原因
const PENDING = 'pending' //等待
const FULFILLED = 'fulfilled'//成功
const REJECTED = 'rejected' //失败
class MyPromise{
    constructor(executor){
        executor(this.resolve,this.reject)
    }
    status = PENDING;
    //成功之后的值
    value = undefined;
    //失败后的原因
    reason =undefined;
    resolve = value =>{
        //如果状态不是等待,阻止程序向下执行
        if(this.status !== PENDING) return;
        //将状态更改为成功
        this.status = FULFILLED
        //保存成功之后的值
        this.value =value
    }
    reject = reason => {
        //如果状态不是等待,阻止程序向下执行
        if(this.status !== PENDING) return;
        //将状态更改为失败
        this.status = REJECTED
        this.reason =reason
    }
    then(successCallback,failCallback){
        //判断状态
        if(this.status === FULFILLED){
            successCallback(this.value)
        }
        else if (this.status === REJECTED) {
            failCallback(this.reason)
        }
    }

2.在promise中加入异步执行

  • 如果在执行过程中有异步任务的化,需要等待这个异步走完才执行resolve和reject的回调,此时promise还是pending态的,所有要加入pending态的处理
class MyPromise{
    //...略...
    //成功之后执行的回调
    successCallback = undefined;
    //失败状态的回调
    failCallback = undefined ;
    resolve = value =>{
      	//...略...
        //写了个短路运算
        this.successCallback && this.successCallback(this.value)
    }
    reject = reason => {
     	//...略...
        this.failCallback && this.failCallback(this.reason)
    }
    then(successCallback,failCallback){
       //...略...
        else{
            //等待态
            this.successCallback = successCallback;
            this.failCallback = failCallback
        }
    }
}

3.then方法的多次执行

当then多次调用的时候需要对异步情况此做特殊处理

//将存放回调的字面量改成数组
//成功之后执行的回调
successCallback = [];
//失败状态的回调
failCallback = [] ;

//成功态的回调改成执行数据对第一个,并切出来,根据数组长度判断
// this.successCallback && this.successCallback(this.value)
while(this.successCallback.length){
    this.successCallback.shift()(this.value)
}
// this.failCallback && this.failCallback(this.reason)
while(this.failCallback.length){
    this.failCallback.shift()(this.reason)
}

//等待态,把回调函添加都数组中
this.successCallback.push(successCallback);
this.failCallback.push(failCallback); 

4.then方法实现链式调用

  • 实现then方法的链式调用
    • then方法在promise里面的,我们要实现then,最基本就算是返回一个promise对象
    • 同时then内部代码式同步执行,所以把之前的代码,传入到new promise的执行器中
  • 把上一个then方法的返回值传到下
    • 调用执行器内的resolve,把回调函数的值传到返回的promise对象中
then(successCallback, failCallback) {
    let promise2 = new MyPromise((resolve,reject ) => {
        if (this.status === FULFILLED) {
           let x = successCallback(this.value)
           resolve(x)
        }
        else if (this.status === REJECTED) {
              failCallback(this.reason)            
        } else {
            this.successCallback.push(successCallback);
            this.failCallback.push(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); 
    // }
    return promise2
}
  • 链式调用深入(回顾链式调用实际使用)
    • 判断x的值式普通值还是promise对象
    • 如果是普通值直接调用resolve传出去
    • 如果是promise对象,查看promise对象的返回结果
    • 在根据promise对象的返回结果,决定调用resolve还是调用reject
//把then方法的返回值传到一个处理函数中 
let x = successCallback(this.value)
resolvePromise(x,resolve,reject)
function  resolvePromise(x,resolve,reject){
        //判断是不是Mypromsier的实例化对象
    if(x instanceof MyPromise){
        // 如果返回的promise对象的话我们就用then的方法去判断他有有没有状态改变
        //有的话执行就调用resolve,reject把值传递下去
        // x.then(value => resolve(value),reason => reject(reson))
        // 优化写法
        x.then(resolve,reject)
    }
    else{
        resolve(x)
    }
}

5.then方法链式调用识别Promiese对象自返回

  • promise不允许自返回
    • 在处理返回值函数中传入新的promise和返回值做未必
function resolvePromise(promise2, x, resolve, reject) {
	//把promise2作为参数传入进来去判断
    if (promise2 == x) {
        return reject(new TypeError('不能自返回'))
    }
    if (x instanceof MyPromise) {
        x.then(resolve, reject)
    }
    else {
        resolve(x)
  • 注意的是这列要异步处理不然的话的这个promise2是拿不到,因为是要等代码执行玩才赋值给这个promise2,所以让他异步才能拿到
if (this.status === FULFILLED) {
    setTimeout(() => {
        let x = successCallback(this.value)
        resolvePromise(promise2, x, resolve, reject)
    },0)
}

6.捕获错误接then链式调用其他代码的补充

  • 在promise执行的函数中的错误捕获
constructor(executor) {
    try{
        executor(this.resolve, this.reject)
    }
    catch(e){
        this.reject(e)                                  
    }
}
  • then方法回调函数执行代码错误捕获
if (this.status === FULFILLED) {
    setTimeout(() => {
        try{
            let x = successCallback(this.value)
            resolvePromise(promise2, x, resolve, reject)
        }
        catch(e){ 
            //当执行错误的时候,就把错误信息传递给出去
            reject(e) 
        }        
    },0)
}
 else if (this.status === REJECTED) {
     setTimeout(() => {
         try{
             let x = failCallback(this.reason)
             resolvePromise(promise2, x, resolve, re
         }
         catch(e){
             reject(e)
         }
            
     },0)
 } 
  • pending时候then函数执行代码错误捕获
//当上一个promise状态未改变时候是异步回调函数
this.successCallback.shift()()
this.failCallback.shift()()
else {
    this.successCallback.push(() => {
        setTimeout(() => {
            try {
                let x = successCallback(this.value)
                resolvePromise(promise2, x, resolve, reject)
            }
            catch (e) {
                reject(e)
            }
        }, 0)
    }
    );
    this.failCallback.push(() => {
        setTimeout(() => {
            try {
                let x = failCallback(this.reason)
                resolvePromise(promise2, x, resolve, reject)
            }
            catch (e) {
                reject(e)
            }
        }, 0)
    });
}

7.then方法的参数是可选参数

  • then方法内可以不传递参数。就把原来的值传递和状态
successCallback = successCallback? successCallback : value => value
failCallback = failCallback? failCallback : reason => {throw reason} //这里需要抛出错误,不然又回到resolve

8.all方法实现

  • promise.all(),用来解决异步代码的并发问题,它允许我们根据异步代码的调用顺序去得到。
    • promise.all(['a','b',p1(),p2(),'c']) => result -- ['a','b',p1(),p2(),'c']
    • promise.all返回值也是一个promise对象
    • 如果all方法都是成功,则返回是成功状态,有一个失败则返回失败状态
    • all是一个静态方法
//根据promise的调用,Promise.all()是一个静态方法
static all(array) {
    let result = [];
    let index = 0;
    return new MyPromise((resolve, reject) => {
        // 需要在内部定义这个添加结果的方法,不然拿不到的resolve
        function addData(key, value) {
            result[key] = value
            // 定义一个计数器,当执行这个addData的时候就加以,就可以避免异步操作的返回空值
            index++;
            if (index === array.length) {
                resolve(result)
            }
        }
        for (let i = 0; i < array.length; i++) {
            let current = array[i];
            if (current instanceof MyPromise) {
                //promise对象的话就执行,参考类似调用then的链式调用
                //如果是promise是成功态的就把值押入到result数组中
                //失败态就直接抛出
                current.then(value => addData(i, value), reject)
            }
            else {
                //普通值
                addData(i, array[i]);
            }
            // resolve(result)
        }
    })
}

9.resolve方法实现

  • resolve(),如果是传递一个值,就返回一个promise对象,并把值传递下去
  • 如果是promsie对象,就把这个promise原封不动返回出去
  • resolve(),方法的作用就是把传递过去的值转化成一个promise对象
 static resolve(value) {
     if(value instanceof MyPromise) return value;
     return new MyPromise(resolve => resolve(value))
 }

10.finally方法实现

  • finally方法无论,promise对象是成功还是失败,里面对回调函数还是会被执行一次
  • finally方法之后调用then方法能够获取当前promise对象的最终返回值
    • 但是要注意调用的then方法是要等待这个finally执行完毕后在执行
 finally(callback){
     // then方法是可以获取当前的状态值,这样可以把当前的壮态值传递给下一个then跟里面内容无关的
     return this.then( value => {
         // callback()
         // return value
         //这一步可以解决finlly的异步问题,到callback执行完成后再往下走
         //通过调用resolve方法把传递值转化未promise对象,实现异步处理
         return MyPromise.resolve(callback()).then(()=>{value})
     }, reason => {
         // callback()
         // throw reason
         return MyPromise.resolve(callback()).then(()=>{throw reason})
     })
 }

11catch方法实现

  • catch方法就是用链式调用处理错误方法
catch (failCallback){
    return this.then(undefined,failCallback)
}

12.完整代码

const PENDING = 'pending' 
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected' 
class MyPromise {
    constructor(executor) {
        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 = reason => {
        if (this.status !== PENDING) return;
        this.status = REJECTED
        this.reason = reason
        while (this.failCallback.length) {
            this.failCallback.shift()()
        }
    }
    then(successCallback, failCallback) {
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => { throw reason }
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        let x = successCallback(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    }
                    catch (e) {
                        reject(e)
                    }
                }, 0)
            }
            else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = failCallback(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    }
                    catch (e) {
                        reject(e)
                    }
                }, 0)
            }
            else {
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = successCallback(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        }
                        catch (e) {
                            reject(e)
                        }
                    }, 0)
                }
                );
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failCallback(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        }
                        catch (e) {
                            reject(e)
                        }
                    }, 0)
                });
            }
        })
        return promise2
    }
    finally(callback){
        return this.then( value => {
            return MyPromise.resolve(callback()).then(()=>{value})
        }, reason => {
            return MyPromise.resolve(callback()).then(()=>{throw reason})
        })
    }
    catch (failCallback){
        return this.then(undefined,failCallback)
    }
    static all(array) {
        let result = [];
        let index = 0;
        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value
                index++;
                if (index === 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), reject)
                }
                else {
                    addData(i, array[i]);
                }
            }
        })
    }
    static resolve(value) {
        if(value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value))
    }
}
function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 == x) {
        return reject(new TypeError('不能自返回'))
    }
    if (x instanceof MyPromise) {
        x.then(resolve, reject)
    }
    else {
        resolve(x)
    }
}