Promise源码解读(ES6)

224 阅读7分钟

一、构造函数

Promise是如下这样使用的所有Promise应该是一个构造函数或者类(es6),而且在new构造函数是传入了一个函数参数,所以在构造函数中应该调用这个参数。

const p = new Promise((resolve, reject) => {})

所以Promise应该是这样的

class MyPromise {
    constructor(executor){
       executor(resolve, reject);
    }
}
//或者 构造函数
function Promise(excutor) {
    excutor(resolve, reject);
}

在调用参数函数(executor)是需要传入两个函数resolve和reject两个函数,需要定义这两个函数,这两个函数的作用相同①修改状态②保存参数③调用对应的回调函数。

// 声明常量确定状态
const PENDING = 'PENDING';
const RESOLVED ='RESOLVED';
const REJECTED = 'REJECTED';
 
class MyPromise {
    constructor(executor){
        this.status=PENDING;//等待状态
        this.value =undefined;//then方法要访问到所以放到this上
        this.reason=undefined;//then方法要访问到所以放到this上
        this.onResolvedCallbacks=[];// 专门存放成功的回调函数
        this.onRejectedCallbacks=[];// 专门存放成功的回调函数
        let resolve=(value)=>{
            if(this.status === PENDING){// 保证只有状态是等待态的时候才能更改状态
                this.value=value;
                this.status=RESOLVED;
                // 需要让成功的方法依次执行
                setTimeout(()=>{
                    this.onResolvedCallbacks.forEach(fn=>fn())
                }
                )
            }
        };
        let reject=(reason)=>{
            if(this.status === PENDING){// 保证只有状态是等待态的时候才能更改状态
                this.reason=reason;
                this.status=REJECTED;
                // 需要让失败的方法依次执行
                setTimeout(()=>{
                    this.onRejectedCallbacks.forEach(fn=>fn())
                }
                )
            }
        };
        // 执行executor传入我们定义的成功和失败函数:把内部的resolve和reject传入executor中用户写的resolve, reject
        try{
            executor(resolve, reject);
        }catch(e){
            console.log('catch错误', e);
            reject(e); //如果内部出错 直接将error手动调用reject向下传递
        }
    }
  }

二 、原型方法 .then

onfulfilled = typeof onfulfilled==='function' ? onfulfilled : value=>value //向后传递成功的value
 // 指定默认的失败回调函数(实现错误/异常穿透的关键点)
onrejected = typeof onrejected==='function' ? onrejected : error=>{throw error} //向后传递失败的reason

如果.then方法中没有指定成功或失败的回调函数将成功和失败的结果传递下去。

因为then方法后边还能链式调用所有方法返回的还应是一个promise所以使用了 return new MyPromise((resolve,reject)=>{}

所以在 return new MyPromise((resolve,reject)=>{}中要能知道.then方法中参数函数的执行结果根据结果,所以创建了一个函数,函数有两个参数,第一个参数是函数,二是调用一参数函数的参数,根据第一个函数的结果执行return new MyPromise((resolve,reject)=>{}中的 resolve,reject

 // 函数分装,根据then()参数执行的结果确定上方promise的返回值
let handle =(callback,values)=>{
     // 1.如果抛出异常,return的promise的失败。reason就是err
      // 2.如果回调函数不是promis,return的promis就成功,value就是返回的值
       // 3.如果回调函数是promis,return的promis就是回调中的这个promise的结果,value就是返回的值
       try{
           const result=callback(values);
           if(result instanceof MyPromise){
                  // 3.如果回调函数是promis,return的promis就是回调中的这个promise的结果,value就是返回的值
                   result.then(
                   	 value =>{
                         resolve(value)
                     },
                      reason =>{
                            reject(reason)
                      }
                     )
              }else{
                 // 2.如果回调函数不是promis,return的promis就成功,value就是返回的值
                  resolve(result)
               }
          }catch(error){
              //1.如果抛出异常,return的promise的失败。reason就是err
              reject(error)
           }
 }
// 如果状态还没改变,异步情况将实参的函数保存起来,等状态改变了在调用
            if(this.status === PENDING){
                // this.onResolvedCallbacks.push(onfulfilled); 这种写法可以换成下面的写法,多包了一层,这叫面向切片编程,可以加上自己的逻辑
                this.onResolvedCallbacks.push(()=>{
                    // 自己的逻辑
                    // 当状态没发生改变时,将then()的参数函数保存起来等状态发生改变在执行,保存时不是直接保存而是声明一个箭头函数
                    // 将箭头函数保存起来,在箭头函数中调用then()参数的函数,为的是在此处执行then()参数的函数能让其能访问到then方法
                    // 中返回的MyPromise中的resolve,reject
                    handle (onfulfilled,this.value)
                });
                this.onRejectedCallbacks.push(()=>{
                    // 自己的逻辑
                    handle (onrejected ,this.reason);
                });
            }else if (this.status === RESOLVED) {
                // 如果状态已经变化直接执行实参中的函数
                setTimeout(()=>{
                    handle (onfulfilled,this.value)
                })
                
            }else if (this.status === REJECTED) {
                 setTimeout(()=>{
                    handle (onrejected ,this.reason);
                })
                
            }

通过上方的代码能进一步了解为什么要定义函数,当状态没有改变时,向类Promise中的公有属性中添加方法,等待状态改变后执行。而添加的方法是一个箭头函数,状态改变后执行的是箭头函数,执行箭头函数会调用handle 方法,然后执行对应的对原型方法 .then的参数函数。如果状态已经改变,就直接执行handle函数。

原型方法 .then的整体代码

// 原型方法
    then(onfulfilled,onrejected){
        onfulfilled = typeof onfulfilled==='function' ? onfulfilled : value=>value //向后传递成功的value
        // 指定默认的失败回调函数(实现错误/异常穿透的关键点)
        onrejected = typeof onrejected==='function' ? onrejected : error=>{throw error} //向后传递失败的reason
        // 因为then 能链式编程所有返回的需要是一个promise
        return new MyPromise((resolve,reject)=>{
            // 函数分装,根据then()参数执行的结果确定上方promise的返回值
            let handle =(callback,values)=>{
                // 1.如果抛出异常,return的promise的失败。reason就是err
                // 2.如果回调函数不是promis,return的promis就成功,value就是返回的值
                // 3.如果回调函数是promis,return的promis就是回调中的这个promise的结果,value就是返回的值
                try{
                    const result=callback(values);
                    if(result instanceof MyPromise){
                        // 3.如果回调函数是promis,return的promis就是回调中的这个promise的结果,value就是返回的值
                        result.then(
                            value =>{
                                resolve(value)
                            },
                            reason =>{
                                reject(reason)
                            }
                        )
                    }else{
                        // 2.如果回调函数不是promis,return的promis就成功,value就是返回的值
                        resolve(result)
                    }
                }catch(error){
                    //1.如果抛出异常,return的promise的失败。reason就是err
                    reject(error)
                }
            }
            // 如果状态还没改变,异步情况将实参的函数保存起来,等状态改变了在调用
            if(this.status === PENDING){
                // this.onResolvedCallbacks.push(onfulfilled); 这种写法可以换成下面的写法,多包了一层,这叫面向切片编程,可以加上自己的逻辑
                this.onResolvedCallbacks.push(()=>{
                    // 自己的逻辑
                    // 当状态没发生改变时,将then()的参数函数保存起来等状态发生改变在执行,保存时不是直接保存而是声明一个箭头函数
                    // 将箭头函数保存起来,在箭头函数中调用then()参数的函数,为的是在此处执行then()参数的函数能让其能访问到then方法
                    // 中返回的MyPromise中的resolve,reject
                    handle (onfulfilled,this.value)
                });
                this.onRejectedCallbacks.push(()=>{
                    // 自己的逻辑
                    handle (onrejected ,this.reason);
                });
            }else if (this.status === RESOLVED) {
                // 如果状态已经变化直接执行实参中的函数
                setTimeout(()=>{
                    handle (onfulfilled,this.value)
                })
                
            }else if (this.status === REJECTED) {
                 setTimeout(()=>{
                    handle (onrejected ,this.reason);
                })
                
            }
            
        })  
    }

三、其他方法

catch(errCallback) {
        return this.then(undefined, errCallback);
    }
    // reject 方法(静态方法)返回一个指定的reason的失败promise
    static reject(reason){
        return new MyPromise((resolve,reject)=>{
            reject (reason)
        })
    }
    // resolve方法(静态方法)返回一个指定结果的成功reason
    static resolve(value){
        return new MyPromise((resolve,reject)=>{
            if(value instanceof MyPromise){
                value.then(resolve,reject)
            }else{  //value不是promise
                resolve(value)
            }
        })
    }
    // 返回一个promise,只有都成功返回成功,有一个失败返回失败
    static all(promises){
        const values = new Array (promises.length);
        let resolvedCount = 0;
        return new MyPromise((resolve,reject)=>{
            promises.forEach((p,index)=>{
                this.resolve(p).then(
                    value =>{
                        resolvedCount++
                        values[index] =value
                        if(resolvedCount===promises.length){
                            resolve(values)
                        }
                    },
                    reason=>{
                        reject(reason)
                    }
                )

            })
        })
    }
	static race (list) {
      return new MyPromise((resolve, reject) => {
        list.forEach((p,index)=>{
            this.resolve(p).then(
                value=>{
                    resolve(value)
                },
                reason =>{
                    reject(reason)
                }
            )
        })
        
      })
    }

① 原型catch方法,调用原型方法then成功参数为undefined

② 静态方法reject返回一个错误结果的promise,

③ 静态方法resolve方法(静态方法)返回一个指定结果的成功reason,会检查一下参数是不是promise,如果是就执行then方法,并将结果返回,如果不是直接返回。

④ 静态方法all方法返回一个promise,只有都成功返回成功,有一个失败返回失败,会对所有参数进行forEach循环。

⑤ 静态方法race方法返回一个promise,有一个成功就返回成功,有一个失败就返回失败。