Promise规范及应用

Promise规范及应用


Promise规范


术语

  1. promise 是⼀个有then⽅法的对象或者是函数,⾏为遵循本规范
  2. thenable是一个有then方法或者是函数
  3. value是promise状态成功时的值,也就是resolve的参数,包括各种数据类型, 也包括 undefined/thenable 或者是 promise
  4. reason是promise状态失败的值,也就是reject的参数,表示拒绝的原因
  5. exception 是一个使用throw抛出的异常值

规范

promise states

Promise应该有三种状态

  1. pending
    • 初始的状态,可改变
    • 一个promise在resolve或者reject前都处于这个状态
    • 可以通过resolve → fulfilled状态
    • 可以通过 reject → rejecteed 状态
  2. fulfulled
    • 最终态,不可改变
    • 一个promise被resolve后就会变成这个状态
    • 必须拥有一个value值
  3. rejected
    • 最终态,不可改变
    • 一个promise被reject后会变成这个状态
    • 必须拥有一个reason

promise的状态流转是这样的:

pending → resolve(value) → fulfilled

pending → reject(reason) → rejecteed

then

promise应该提供一个then方法,用来访问最终的结果,无论是value还是reason

promise.then(onFulfilled,onRejected)
  1. 参数要求

    • onFulfilled 必须是函数类型,如果不是函数,应该被忽略
    • onRejected 必须是函数类型,如果不是函数,应该被忽略
  2. onFulfilled特性

    • 在promise变成fulfilled时,应该调用onFulfilled,参数时value
    • 在promise变成fulfilled之前,不应该被调用
    • 只能被调用一次(所以在实现的时候需要⼀个变量来限制执⾏次数)
  3. onRejected特性

    • 在promise变成rejected时,应该调用onRejected,参数是reason
    • 在promise变成rejected之前,不应该被调用
    • 只能被调用一次(所以在实现的时候需要⼀个变量来限制执⾏次数)
  4. onFulfilled和onRejected应该是微任务

    • 这里使用queueMicrotask来实现微任务的调用
  5. then方法可以被调用多次

    • promise状态变成fulfilled后,所有的onFulfilled回调都需要按照then的顺序执行,也就是按照注册顺序执行(所以在实现的时候需要⼀个数组来存放多个onFulfilled的回调)
    • promise状态变成rejected后,所有的onRejected回调都需要按照then的顺序执行,也就是按照注册顺序执行(所以在实现的时候需要⼀个数组来存放多个onRejected的回调)
  6. 返回值

    then应该返回一个promise

    newPromise=promise.then(onFulfilled,onRejected);
    
    • onFulfulled或onRejected执行的结果为x,调用resolvePromise
    • 如果onFulfilled或者onRejected执行时抛出异常e,newPromise需要被reject
    • 如果onFulfilled不是一个函数,newPromise以promise的value触发fulfilled
    • 如果onRejected不是一个函数,newPromise以promise的reason触发rejected
  7. resolvePromise

    resolvePromise(newPromise,x,resolve,reject)
    
    • 如果newPromise和x相等,那么 reject TypeError

    • 如果x是一个promise

      ​ 如果x是pending态,那么promise必须要在pending,直到 x 变成 fulfilled or rejected.

      ​ 如果 x 被 fulfilled, fulfill promise with the same value.

      ​ 如果 x 被 rejected, reject promise with the same reason.

    • 如果 x 是⼀个 object 或者 是⼀个 function

      let then = x.then.

      如果 x.then 这步出错,那么 reject promise with e as the reason.

      如果 then 是⼀个函数,then.call(x, resolvePromiseFn, rejectPromise)

      ​ resolvePromiseFn 的 ⼊参是 y, 执⾏ resolvePromise(newPromise, y, resolve, reject);

      ​ rejectPromise 的 ⼊参是 r, reject promise with r

      ​ 如果 resolvePromise 和 rejectPromise 都调⽤了,那么第⼀个调⽤优先,后⾯的调⽤忽
      略。

      ​ 如果调⽤then抛出异常e

      ​ 如果 resolvePromise 或 rejectPromise 已经被调⽤,那么忽略

      ​ 则,reject promise with e as the reason

      ​ 如果 then 不是⼀个function. fulfill promise with x

实现一个promise

初始化

平常⽤promise的时候, 是通过new关键字来new Promise(),所以应该⽤构造函数或者class来实现

class MPromise{
  constructor(){
    
  }
}

定义三种状态

const PENDING='pending';
const FULFILLED='fulfilled';
const REJECTED='rejected';

设置初始状态

class MPromise{
  constructor(){
    // 初始状态为pending
    this.status=PENDING;
    this.value=null;
    this.reason=null;
  }
}

resolve 和 reject方法

这两个⽅法是要更改status的, 从pending改到fulfilled/rejected.

这两个函数的⼊参分别是value 和 reason.

class MPromise{
  
  constructor(){
    // 初始状态为pending
    this.status=PENDING;
    this.value=null;
    this.reason=null;
  }
  
  resolve(value){
    if(this.status===PENDING){
      this.status=FULFILLED;
      this.value=value;
    }
  }
  
  reject(reason){
    if(this.status===PENDING){
      this.status=REJECTED;
      this.reason=reason;
    }
  }
}

promise的入参应该是个函数

  1. ⼊参是⼀个函数, 函数接收resolve和reject两个参数.
  2. 注意在初始化promise的时候, 就要执⾏这个函数, 并且有任何报错都要通过reject抛出去
class MPromise{
  
  constructor(fn){
    // 初始状态为pending
    this.status=PENDING;
    this.value=null;
    this.reason=null;
    try{
      fn(this.resolve.bind(this),this.reject.bind(this));
    }catch(e){
      this.reject(e);
    }
  }
  
  resolve(value){
    if(this.status===PENDING){
      this.status=FULFILLED;
      this.value=value;
    }
  }
  
  reject(reason){
    if(this.status===PENDING){
      this.status=REJECTED;
      this.reason=reason;
    }
  }
}

then方法

1.then接收两个参数, onFulfilled 和 onRejected

then(onFulfilled,onRejected){}

2.检查并处理参数, 之前提到的如果不是function, 就忽略. 这个忽略指的是原样返回value或者reason.

首先判断参数是否是函数类型

isFunction(param){
  return typeof param==='function';
}

then

then(onFulfilled, onRejected) {
 	const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled :(value) => {
 		return value;
 	};
 	const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason)=> {
 		throw reason
 	};
 }

3.根据promise的状态,调用不同的函数

当在then函数被调⽤的瞬间就会执⾏. 那这时候如果status还没变成fulfilled或者rejected怎么办, 很有可能还是pending的

那么我们⾸先要拿到所有的回调, 然后才能在某个时机去执⾏他. 新建两个数组, 来分别存储成功和失败的回调, 调⽤then的时候, 如果还是pending就存⼊数组.

then(onFulfilled, onRejected) {
 	const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled :(value) => {
 		return value;
 	};
 	const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason)=> {
 		throw reason
 	};
  switch(this.status){
    case FULFILLED:{
      fulFilledFn(this.value);
      break;
    }
    case REJECT:{
      rejectedFn(this.reason);
      break;
    }
      case PENDING: {
 		this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled);
 		this.REJECTED_CALLBACK_LIST.push(realOnRejected);
 		break;
 	}
  }
 }
class MPromise {
   FULFILLED_CALLBACK_LIST = [];
   REJECTED_CALLBACK_LIST = [];
   _status = PENDING;

   constructor(fn) {
       this.status = PENDING;
       this.value = null;
       this.reason = null;

       try {
           fn(this.resolve.bind(this), this.reject.bind(this));
       } catch (e) {
           this.reject(e);
       }
   }
   reason(value){}
   reject(reason){}
   then(onFulfilled, onRejected){
 		const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled :(value) => {
			return value;
		};
		const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason)=> {
			throw reason
		};
 		switch(this.status){
   		case FULFILLED:{
     			fulFilledFn(this.value);
     			break;
   		}
   		case REJECT:{
     			rejectedFn(this.reason);
     			break;
   		}
     		case PENDING: {
				this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled);
				this.REJECTED_CALLBACK_LIST.push(realOnRejected);
				break;
			}
 		}
   }
   isFunction(param){
 		return typeof param==='function';
   }
}

在status发⽣变化的时候, 就执⾏所有的回调.

get status(){
  return this._status;
}
set status(newStatus) {
        this._status = newStatus;
        switch (newStatus) {
            case FULFILLED: {
                this.FULFILLED_CALLBACK_LIST.forEach((callback) => {
                    callback(this.value);
                });
                break;
            }
            case REJECTED: {
                this.REJECTED_CALLBACK_LIST.forEach((callback) => {
                    callback(this.reason);
                });
                break;
            }
        }
    }

then的返回值

如果 onFulfilled 或者 onRejected 抛出⼀个异常 e ,则 newPromise 必须拒绝执⾏,并返回拒因 e。

then(onFulfilled,onRejected){
        const fulFilledFn=this.isFunction(onFulfilled) ? onFulfilled : (value)=>{
            return value;
        }
        const rejectedFn=this.isFunction(onRejected) ? onRejected : (reason)=>{
            throw reason;
        }

        const fulfilledFnCatch=(resolve,reject,newPromise)=>{
          try{
            fulFilledFn(this.value);
          }catch(error){
            reject(error)
          }
        };

        const rejectedFnCatch=(resolve,reject,newPromise)=>{
            try{
            	rejectedFn(this.reason);
          	}catch(error){
            	reject(error)
          	}
        }

        switch(this.status){
            case FULFILLED : {
                const newPromise=new MPromise(fulfilledFnCatch);
                return newPromise;
            }
            case REJECTED : {
                const newPromise=new MPromise(rejectedFnCatch);
                return newPromise;
            }
            case PENDING : {
                const newPromise=new MPromise((resolve,reject)=>{
                    this.FULFILLED_CALLBACK_LIST.push(()=>fulfilledFnCatch(resolve,reject));
                    this.REJECTED_CALLBACK_LIST.push(()=>rejectedFnCatch(resolve,reject));
                })
                return newPromise;
            }
        }
    }

如果 onFulfilled 不是函数且 promise 成功执⾏, newPromise 必须成功执⾏并返回相同的值

const fulfilledFnCatch=(resolve,reject,newPromise)=>{
          try{
            fulFilledFn(this.value);
            resolve(this.value);
          }catch(error){
            reject(error)
          }
}

如果 onRejected 不是函数且 promise 拒绝执⾏, newPromise必须拒绝执⾏并返回相同的据因。

需要注意的是,如果promise的onRejected执⾏成功了,newPromise应该被resolve

const rejectedFnWithCatch = (resolve, reject) => {
 	try {
 		rejectedFn(this.reason);
 		if (this.isFunction(onRejected)) {
 			resolve();
 		}
 	} catch (e) {
 		reject(e);
 	}
 }

如果 onFulfilled 或者 onRejected 返回⼀个值 x ,则运⾏resolvePromise⽅法

then(onFulfilled,onRejected){
        const fulFilledFn=this.isFunction(onFulfilled) ? onFulfilled : (value)=>{
            return value;
        }
        const rejectedFn=this.isFunction(onRejected) ? onRejected : (reason)=>{
            throw reason;
        }

        const fulfilledFnCatch=(resolve,reject,newPromise)=>{
                try{
                    if(!this.isFunction(onFulfilled)){
                        resolve(this.value);
                    }else{
                        const x=fulFilledFn(this.value);
                        this.resolvePromise(newPromise,x,resolve,reject);
                    }
                }catch(e){
                    reject(e);
                } 
        };

        const rejectedFnCatch=(resolve,reject,newPromise)=>{
                try{
                    if(!this.isFunction(onRejected)){
                        reject(this.reason);
                    }else{
                        const x=rejectedFn(this.reason);
                        this.resolvePromise(newPromise,x,resolve,reject);
                    }
                }catch(e){
                    reject(e);
                }
        }

        switch(this.status){
            case FULFILLED : {
                const newPromise=new MPromise((resolve,reject)=>fulfilledFnCatch(resolve,reject,newPromise));
                return newPromise;
            }
            case REJECTED : {
                const newPromise=new MPromise((resolve,reject)=>rejectedFnCatch(resolve,reject,newPromise));
                return newPromise;
            }
            case PENDING : {
                const newPromise=new MPromise((resolve,reject)=>{
                    this.FULFILLED_CALLBACK_LIST.push(()=>fulfilledFnCatch(resolve,reject,newPromise));
                    this.REJECTED_CALLBACK_LIST.push(()=>rejectedFnCatch(resolve,reject,newPromise));
                })
                return newPromise;
            }
        }
 }

resolvePromise

resolvePromise(newPromise, x, resolve, reject) {
        if (newPromise === x) {
            return reject(new TypeError("xxxxxxxxxxxxxxxx"));
        }

        if (x instanceof MPromise) {
            x.then(
                (y) => {
                    this.resolvePromise(newPromise, y, resolve, reject);
                },
                reject
            );
        } else if (typeof x === 'object' || this.isFunction(x)) {
            if (x === null) {
                return resolve(x);
            }

            let then = null;

            try {
                then = x.then;
            } catch (error) {
                resolve(error);
            }

            if (this.isFunction(then)) {
                let called = false;
                try {
                    then.call(
                        x,
                        (y) => {
                            if (called) {
                                return;
                            }
                            called = true;
                            this.resolvePromise(newPromise, y, resolve, reject);
                        },
                        (r) => {
                            if (called) {
                                return;
                            }
                            called = true;
                            reject(r);
                        }
                    )
                } catch (error) {
                    if (called) {
                        return;
                    }
                    reject(error);
                }
            } else {
                resolve(x);
            }

        } else {
            resolve(x);
        }
    }

onFulfilled 和 onRejected 是微任务

⽤queueMicrotask包裹执⾏函数

then(onFulfilled,onRejected){
        const fulFilledFn=this.isFunction(onFulfilled) ? onFulfilled : (value)=>{
            return value;
        }
        const rejectedFn=this.isFunction(onRejected) ? onRejected : (reason)=>{
            throw reason;
        }

        const fulfilledFnCatch=(resolve,reject,newPromise)=>{
            queueMicrotask(()=>{
                try{
                    if(!this.isFunction(onFulfilled)){
                        resolve(this.value);
                    }else{
                        const x=fulFilledFn(this.value);
                        this.resolvePromise(newPromise,x,resolve,reject);
                    }
                }catch(e){
                    reject(e);
                }
            });
        };

        const rejectedFnCatch=(resolve,reject,newPromise)=>{
            queueMicrotask(()=>{
                try{
                    if(!this.isFunction(onRejected)){
                        reject(this.reason);
                    }else{
                        const x=rejectedFn(this.reason);
                        this.resolvePromise(newPromise,x,resolve,reject);
                    }
                }catch(e){
                    reject(e);
                }
            });
        }

        switch(this.status){
            case FULFILLED : {
                const newPromise=new MPromise((resolve,reject)=>fulfilledFnCatch(resolve,reject,newPromise));
                return newPromise;
            }
            case REJECTED : {
                const newPromise=new MPromise((resolve,reject)=>rejectedFnCatch(resolve,reject,newPromise));
                return newPromise;
            }
            case PENDING : {
                const newPromise=new MPromise((resolve,reject)=>{
                    this.FULFILLED_CALLBACK_LIST.push(()=>fulfilledFnCatch(resolve,reject,newPromise));
                    this.REJECTED_CALLBACK_LIST.push(()=>rejectedFnCatch(resolve,reject,newPromise));
                })
                return newPromise;
            }
        }
    }

catch方法

catch(onRejected){
        return this.then(null,onRejected);
}

promise.resolve

将现有对象转为Promise对象,如果 Promise.resolve ⽅法的参数,不是具有 then ⽅法的对象(⼜称 thenable 对象),则返回⼀个新的 Promise 对象,且它的状态为fulfilled。

static resolve(param) {
 	if (param instanceof MyPromise) {
 		return param;
 	}
 	return new MyPromise(function (resolve) {
 		resolve(param);
 	});
 }

promise.reject

返回⼀个新的Promise实例,该实例的状态为rejected。Promise.reject⽅法的参数reason,会被传递给实例的回调函数。

static reject(reason) {
 	return new MPromise((resolve, reject) => {
 		reject(reason);
 	});
 }

promise.race

const p = Promise.race([p1, p2, p3]);

该⽅法是将多个 Promise 实例,包装成⼀个新的 Promise 实例。

只要p1、p2、p3之中有⼀个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise 实例的返回值,就传递给p的回调函数。

static race(promiseList) {
 	return new MPromise((resolve, reject) => {
 		const length = promiseList.length;
 		if (length === 0) {
 			return resolve();
 		} else {
 			for (let I = 0; I < length; I++) {
 				MPromise.resolve(promiseList[I]).then(
 					(value) => {
 						return resolve(value);
 					},
 					(reason) => {
 						return reject(reason);
 					});
 				}
 			}
 		});
 }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alonzo de blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值