天天看点

手写Promise原理实现

从构造函数开始

  1. Promise就是一个类,在执行这个类的时候需要传递一个执行器进去,执行器会立即执行。
  2. Promise中有三种状态 分别为:成功

    fulfilled

    失败

    rejected

    等待

    pending

    ,一旦状态确定就不可更改。
//Promise 类核心逻辑实现
const PENDING = 'pending';//等待
const FULFILLED = 'filfulled';//成功
const REJECTED = 'rejected';//失败

class Promise {
    //构造函数
    constructor(executor){
        //try catch为了捕获执行器中的错误 从而抛出异常
        try{
            //执行器:立即执行
            executor(this.resolve,this.reject)
        }catch(e){
            this.reject(e)
        }
    }
    //promise状态:先定义为peding,在resolve和reject中改变状态
    status = PENDING;
	//成功之后的值
	value = undefined;
	//失败后的原因
	reason = undefined;
	//成功回调函数队列
	successCallback = [];
	//失败回调函数队列
	failCallback = [];
}

module.exports = Promise
           

resolve属性的定义

resolve属性用来修改Promise的状态:pending => fulfilled

//构造函数中
resolve = value =>{
        //如果不是等待,则阻止程序向下执行
        if(this.status !=== 'pending') return;
        //将状态更改为成功
        this.status = FULFILLED
        //保存成功之后的值
        this.value = value
        //判断成功回调是否存在 如果存在 => 调用:调用完后删除并返回第一个回调的值
        while(this.successCallback.length) this.successCallback.shift()()
}
           

reject属性的定义

reject属性用来修改Promise的状态:pending => rejected

//构造函数中 
reject = reason => {
        //如果状态不是等待,阻止程序向下执行
        if(this.status !== 'pending') return;
        //将状态更改为失败
        this.status = REJECTED
        //保存失败之后的原因
        this.reason = reason
        //判断失败回调是否存在 如果存在 调用
        white(this.failCallback.length) this.failCallback.shift()()
    }
           

then方法的实现

  1. then方法是被定义在原型对象中的。
  2. then支持两个参数,分别是成功和失败的回调,而且这两个参数可传可不传。
  3. then方法内部做的事情就是判断状态:如果状态是成功,调用成功的回调函数 ,如果状态是失败,则调用失败回调函数。
  4. 因为有异步任务的情况,并且支持多个回调,所以我们需要对回调函数采用数据进行储存,所以上面定义了失败和成功的回调函数队列。
  5. then的返回结果也是Promise对象
//构造函数中
then(successCallback,failCallback){
    //当调用then方法的时候不传递参数,则Promise状态会依次向后传递,直到传递给有回调的then方法
    successCallback = successCallback ? successCallback : value => value
    failCallback = failCallback ? failCallback : reason => { throw reason }
    
    let promise2 = new Promise((resolve,reject) => {
        let that = this
        if(this.status === FULFILLED){
            //为了变为异步操作
            setTimeout(()=>{
                //try catch为了捕获错误,抛出异常
                try{
                    let x = successCallback(this.value)
                    //判断x的值是普通值还是Promise对象:如果是普通值,直接调用resolve / 如果是Promise对象,查看Promise对象返回的结果。
                    //然后再根据Promise对象返回的结果,决定调用resolve 还是调用reject
                    resolvePromise(promise2,x,resolve,reject)
                }catch(e){
                    reject(e)
                }
            },0)
        }else {
            //有异步任务时:等待
            //将成功回调和失败回调储存起来
            this.successCallback.push(()=>{
                //为了变为异步操作
                setTimeout(()=>{
                	//try catch为了捕获错误,抛出异常
                	try{
                    	let x = successCallback(this.value)
                    	//判断x的值是普通值还是Promise对象:如果是普通值,直接调用resolve / 如果是Promise对象,查看Promise对象返回的结果。
                    	//然后再根据Promise对象返回的结果,决定调用resolve 还是调用reject
                    	resolvePromise(promise2,x,resolve,reject)
                	}catch(e){
                    	reject(e)
                	}
            	},0)
            });
            this.failCallback.push(()=>{
                //为了变为异步操作
            	setTimeout(()=>{
                	//try catch为了捕获错误,抛出异常
                	try{
                    	let x = successCallback(this.value)
                    	//判断x的值是普通值还是Promise对象:如果是普通值,直接调用resolve / 如果是Promise对象,查看Promise对象返回的结果。
                    	//然后再根据Promise对象返回的结果,决定调用resolve 还是调用reject
                    	resolvePromise(promise2,x,resolve,reject)
                	}catch(e){
                    	reject(e)
                	}
            	},0)
            })
        }
    })
    return promise2;
}


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

catch方法的实现

  1. catch方法用来处理当前这个Promise最终的状态为失败的情况。
  2. 当我们调用then方法时 是可以不传递失败回调的 那么失败回调就会被catch捕获并传入catch方法的回调函数。
  3. catch不是静态方法,需要定义在Promise的原型上
//构造函数中
catch(failCallback){
    return this.then(undefined,failCallback)
}
           

finally方法的实现

  1. 无论当前的这个Promise对象是成功的还是失败的 finally当中的函数总会被执行一次。
  2. finally方法的后面我们可以链式调用then方法 来得到当前这个Promise最终返回的结果。
  3. finally不是静态方法,需要定义在Promise的原型上
  4. 需要实现链式调用
//构造函数中
finally(callback){
    //调用then方法来得到当前Promise的状态
    //因为then方法就返回一个Promise,所以直接return
    //要等待异步操作完成后,后面的then才能执行
    return this.then(value => {
		//如果callback返回值是普通值,那么就转换成Promise等待执行完成,后面的then再执行,如果返回的是Promise 还是等待执行完成在执行
        return Promise.resolve(callback()).then(()=>value)
    },reason => {
        return Promise.resolve(callback()).then(()=>{ throw reason })
    })
}
           

Promise.resolve方法的实现

  1. Promise.resolve 的作用就是将里面的值转化为promise对象。
  2. Promise.resolve 是一个静态方法。
//构造函数中
static resolve(value){
    //判断是普通值还是Promise对象,如果是Promise对象就原封不动的放回出去,如果是普通值,那就创建一个Promise将普通值包裹进去返回出去。
    if(value instanceof Promise) return value;
    return new Promise(resolve => resolve(value));
}
           

Promise.reject方法的实现

  1. Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与Promise.resolve方法不一致
  2. Promise.reject是一个静态方法。
// Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。
  // 这一点与Promise.resolve方法不一致
  static reject(reason) {
    return new Promise((undefined, reject) => reject(reason));
  }
           

Promise.all方法的实现

  1. Promise.all方法是解决异步并发问题的,它允许我们按照异步调用的顺序来执行异步方法。
  2. Promise.all是一个静态方法,接收一个数组作为参数。
  3. Promise.all 后面也可以.then链式调用。
//构造函数中
static all(array){
    //准备一个结果数组
    let result = [];
    let index = 0;
    
    //Promise.all 后面也可以.then  所以先返回个Promise对象
    return new Promise((resolve,reject) => {
        //向结果数组中添加返回值
		function addData(key,value){
            result[key] = value
            index ++;
            //for循环是同步执行循环体的,所以我们必须等待异步操作完成之后才能去返回结果
            // 如果index 等于 数组的长度,代表所有的操作已经完毕,就可以返回结果了
            if(index === array.length){
                resolve(result);
            }
        }
        //通过循环的方式,循环进来的数据,在循环过程中判断了循环当前值,判断其是普通值还是Promise对象
        for(let i=0;i<array.length;i++){
            let current = array[i]
            //判断当前的值是普通值还是Promise对象
            if(current instanceof Promise){
                //注:在执行过程中别忘记有异步任务,for循环是不会等待异步操作的,所以当我们调用resolve的时候,还没有执行完,所以结果中会有空值。
                //Promise对象:先执行Promise对象,如果执行成功调用addData方法,反之reject()
                current.then(value => addData(i,value),reason => reject(reason))
            }else {
                //普通值:对应放入结果数组中
                addData(i,array[i])
            }
        }
    })
}
           

Promise.race方法的实现

// race方法
static race (array) {
// race方法,取数组中第一个返回的结果,无论成功或者失败
return new Promise((resolve, reject) => {
  array.forEach(current => {
    if (current instanceof Promise) {
      // promsie对象,返回成功或者失败的结果
      current.then(value => resolve(value), reason => reject(reason))
    } else {
      // 普通值 ,直接返回
      resolve(current)
    }
  })
})
}
           

完整代码

const PENDING = 'pending';//等待
const FULFILLED = 'filfulled';//成功
const REJECTED = 'rejected';//失败

class Promise {
    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
        white(this.failCallback.length) this.failCallback.shift()()
    }
    
    then(successCallback,failCallback){
    	successCallback = successCallback ? successCallback : value => value
    	failCallback = failCallback ? failCallback : reason => { throw reason }
    
    	let promise2 = new Promise((resolve,reject) => {
        	let that = this
        	if(this.status === FULFILLED){
            	setTimeout(()=>{
                	try{
                    	let x = successCallback(this.value)
                    	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 = successCallback(this.value)
                    		resolvePromise(promise2,x,resolve,reject)
                		}catch(e){
                    		reject(e)
                		}
            		},0)
            	})
        	}
    	})
    	return promise2;
	}


	function resolvePromise(promise2,x,resolve,reject){
    	if(promise2 === x){
        	return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    	}
    	if(x instanceof Promise){
        	x.then(resolve,reject)
    	}else {
        	resolve(x)
    	}
	}

	catch(failCallback){
    	return this.then(undefined,failCallback)
	}
	
	finally(callback){
    	return this.then(value => {
        	return Promise.resolve(callback()).then(()=>value)
    	},reason => {
        	return Promise.resolve(callback()).then(()=>{ throw reason })
    	})
	}

	static resolve(value){
    	if(value instanceof Promise) return value;
    	return new Promise(resolve => resolve(value));
	}

  	static reject(reason) {
    	return new Promise((undefined, reject) => reject(reason));
  	}

    static race (array) {
        return new Promise((resolve, reject) => {
          array.forEach(current => {
            if (current instanceof Promise) {
              current.then(value => resolve(value), reason => reject(reason))
            } else {
              resolve(current)
            }
          })
        })
    }

	static all(array){
    	let result = [];
    	let index = 0;
    
    	return new Promise((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 Promise){
                	current.then(value => addData(i,value),reason => reject(reason))
            	}else {
                	addData(i,array[i])
            	}
        	}
    	})
	}
}

module.exports = Promise
           

继续阅读