IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Promise规范及应用 -> 正文阅读

[JavaScript知识库]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);
 					});
 				}
 			}
 		});
 }
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-29 12:02:02  更:2022-04-29 12:02:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:48:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码