promise执行原理

184 阅读3分钟

先看一段平时调用的promise的代码

new Promise((resolve,reject)=>{
    console.log(123)
    resolve('2')
}).then((res)=>{
    console.log(res)
})

在上面代码代码中,可以看到构造函数返回了一个promise实例对象,然后实例对象在调用then函数,这就说明then函数是已经被调用起了

  • 第一步,结合promise的源码来看
代码1
class Promise(){
    construtor(excutor){
    
        //其中的excutor必须是函数
        if(typeof excutor !== function ){
            throw new TypeError('excutor is not a function')
        }
        //定义属性
        this.status = 'pending';
        this.value = undefine;
        this.resolveCallback = [];
        this.rejectCallback = [];
        
        let resolve(result){
            if(this.status == 'pending'){
                this.status = 'resolve';
                this.value = result;
                //为了这段代码是保证then函数后面被执行,所以添加了setTimeout这个宏观任务,因为then是微观任务,这个setTimeout是第二轮的宏观任务,then是第一轮的微观任务,这样是保证then里面的this.resolveCallback.push()代码能够被执行进去,才会有函数被执行
                setTimeout(()=>{   
                    this.resolveCallback.forEach((item)=>{
                        item(result)
                    })
                })
            }
        }
        
        let reject(reason){
            if(this.status == 'pending'){
                this.status = 'reject';
                this.value = reason;
                setTimeout(()=>{
                    this.rejectCallback.forEach((item)=>{item(reason)})
                })
            }
        }
        
        try{
            excutor(resolve,reject)
        }catch(err){
            reject(err)
        }
    }
}

解释:在源码中,我们在promise传入了一个excutor的执行函数,在我们调用的代码resolve('2')之前的时候,status一直保持着pending的状态,then里面的函数(this.resolveCallback.push())已经执行,到代码resolve('2')时,excutour(resolve)调用,状态resolve被凝固,在构造函数里面的resolve方法遍历中,then方法的参数onFufilled函数被执行,恰好证明了promise的resolve成功调用起then的resolve的状态回调,reject也是同理。

  • 第二步 then里面的调用
代码2
在代码1中,添加then方法
then(onFufilled,onRejected){
    //验证传入的onFufilled和onRejected方法必须是函数
    onFufilled  = typeof onFufilled ==='Function' ? onFufilled : function(val){return val};
    onRejected = typeof onRejected ==='Function' ? onRejected :function(val) {return val} ;
    
    
    //返回一个promise才可以保证下面的then的方法的链式调用
    return new Promise((resolve,reject)=>{
        //this指向上一个promise对象,push进去的函数是在构造函数中的resolve方法中执行
        this.resolveCallback.push((result)=>{
            try{
                let x = onFufilled(result)
                //这里的resolve和reject是x这个实例对象的,如果x里面resolve的话就会调用then的成功回调的执行,如果x里面reject的话就会调用then的失败回调的执行
                x instanceof Promise ? x.then(resolve,reject) :resolve(x);
            }catch(e){
                reject(e)
            }
        })
        
          this.rejectCallback.push((result)=>{
            try{
                let x = onRejected(result)
                x instanceof Promise ? x.then(resolve,reject) :resolve(x);
            }catch(e){
                reject(e)
            }
        })
    })
}

解释:then方法,在我们平时调用的promise中,new Promise().then(),已经被调用起了。 在浏览器的执行中,分宏任务和微任务,结合代码1和代码2,分析下new Promise().then()的执行,new Promise是第一宏任务,then是第一微任务,先执行完宏任务,再执行微任务,这是执行的顺序,现在看一下Promise构造函数里面的代码,重点是resolve这个函数,里面有个setTimeout,这是第二个宏观任务,所以,当new Promise里面的代码执行完之后,但是此时的setTimeout没有被执行,此时浏览器已经去执行了then,所以,this.resolveCallback数组才有值,第一微任务执行完之后,才去执行第二宏任务,这个就是resolveCallback里面的函数的调用;

静态方法

第一个:Promise.resolve

Promise.resolve((value)=>{
    return new Promise((resolve,reject)=>{
         try{
            value instanceof Promise ? value.then(resolve,reject) :resolve(value);
        }catch(e){
            reject(e)
        }
    })
})

第二个:Promise.reject

Promise.reject((value)=>{
    return new Promise((resolve,reject)=>{
        reject(value)
    })
})

第三个:Promise.all

Promise.all((promises)=>{
    //传入的参数promises是每个key值为promise对象的数组
    return new Promise((resolve,reject)=>{
        let count =0;
        let promiseLength = promises.length;
        let resolveValue = new Array(promiseLength);
        for(let i=0;i<promiseLength;i++){
            (function(i){
                Promise.resolve(promises[i]).then((res)=>{
                    count++;
                    resolveValue[i] = res;
                    if(count === promiseLength){
                        return resolve(resolveValue)
                    }
                },(err)=>{
                    return reject(err)
                })
            })(i)
        }
    })
})

解释:promise.all对一系列promise实例的触发,每个实例必须全部为resolve的时候,它才返回每个promise实例结果组成的数组。

原型方法

第一个:Promise.prototype.then

参照上面的代码2

第二个:Promise.prototype.catch

Promise.prototype.catch = ((onRejected)=>{
    retrun this.then(null,onRejected)
})