深入理解Promise

Promise原理与简易实现解析
文章详细介绍了Promise的工作原理,包括其状态机模型(pending、fulfilled、rejected),executor函数的角色,以及then、catch和finally方法的使用。此外,还提供了一个简单的Promise类实现,通过setInterval模拟异步操作。最后展示了Promise.all和Promise.race的静态方法,并用实例解释了它们的功能。

一、 Promise原理

借助状态机的概念理解Promise原理,假定Promise实例是一个状态机。

1.1 Promise 状态机:

Promise状态机是Promise实现异步编程的核心手段,这个状态机拥有三种状态status,分别是
 pending----待定
 fulfilled----兑现(亦称解决、resolved)
 rejected----拒绝
Promise状态机的状态status转换只有两种,且这两种转换的过程是单向不可逆的,即
   pending ---->  fulfilled  <=====> 对应的状态转变函数是resolve
   pending ---->  rejected   <=====> 对应的状态转变函数是reject
当我们的状态机发生了转变,我们应该给出相应的处理结果(如fulfilled时,应该返回相应的处理值value;rejected时,应该给出拒绝的理由reason)

1.2 executor

executor接受两个状态转变函数(resolve, reject)作为参数。
当通过new 来生成一个Promise实例时,需要我们传入一个executor 函数,该executor的作用是指定Promise 
状态机的状态转换规则,如状态机在什么时候resolve,并确定fulfilled后应该返回什么值;在什么时候reject,
在rejected时,应给出拒绝的原因。即executor中的代码需要编程人员自行组织。
注意:executor函数中的代码是按照正常执行顺序执行的。

1.3 thenable 接口

在ES中暴露的异步结构中,任何Promise对象都有一个then方法。

1.4 Promise实例的相关方法

then、catch、finally这三个实例函数的执行时机是在Promise状态机的状态发生转变后执行,即异步执行。
then(onFulfilled、onRejected):
    接受两个处理函数onFulfilled、onRejected作为参数。
    当status为fulfilled时,执行onFulfilled。
    当status为rejected是,执行onRejected。
    then的显式返回值会被包装成在个Promise实例中。
catch(onRejected):
    接受一个处理函数onRejected作为参数、在rejected时会执行;
    catch的显式返回值会被包装成在个Promise实例中。
finally(onFinally): 
    接受一个任意处理函数作为参数、无论fulfilled或是rejected都会执行

1.5 Promise的静态方法

resolve(value):
   生成一个fulfilled的Promise实例。
reject(reason): 
   生成一个rejected的Promise实例。
all(args):  
   接受一个Promise实例数组,如果所有Promise实例的状态都为fulfilled,
   生成一个fulfilled的Promise实例;否则生成一个rejected的Promise实例。
   这个方法可用于并发执行。
race(args): 
   接受一个Promise实例数组,生成一个Promise实例,数组中哪个实例的状态先转变,
   则生成的实例的状态与先发生状态转变的实例的状态一致。

二、简陋实现一个Promise类

// 通过上述原理实现一个简陋的Promise类、用setTimeout模拟异步(这种方式有很大的问题)
/**************************************************Promise概述********************************************
	* @title:Promise原理
	* @content:
	* 		理解Promise的两个核心概念:Promise状态机、executor
	* 		Promise 状态机:
	* 			Promise状态机是Promise实现异步编程的核心手段,这个状态机拥有三种状态status,分别是
	* 				  pending----待定
	* 				fulfilled----兑现(亦称解决、resolved)
	* 				 rejected----拒绝
	* 			Promise状态机的状态status转换只有两种,且这两种转换的过程是单向不可逆的,即
	* 				pending ---->  fulfilled  <=====> 对应的状态转变函数是resolve
	*               pending ---->  rejected   <=====> 对应的状态转变函数是reject
	*          当我们的状态机发生了转变,我们应该给出相应的处理结果(如fulfilled时,应该返回相应的处理值value;
	*			rejected时,应该给出拒绝的理由reason)
	*      Promise executor:executor接受两个状态转变函数(resolve, reject)作为参数
	* 			当通过new 来生成一个Promise实例时,需要我们传入一个executor 函数,该executor的作用是指定Promise 
	*          状态机的状态转换规则,如状态机在什么时候resolve,并确定fulfilled后应该返回什么值;在什么时候reject,
	*          在rejected时,应给出拒绝的原因。即executor中的代码需要编程人员自行组织。
	*          注意:executor函数中的代码是按照正常执行顺序执行的。
	*      thenable 接口:
	* 			在ES中暴露的异步结构中,任何Promise对象都有一个then方法。
	* 	   Promise实例的api函数
	* 			then、catch、finally这三个实例函数的执行时机是在Promise状态机的状态发生转变后执行,即异步执行。
	* 			then:接受两个处理函数onFulfilled、onRejected作为参数。
	*               当status为fulfilled时,执行onFulfilled。
	*               当status为rejected是,执行onRejected。
	* 				 then的显式返回值会被包装成在个Promise实例中
	* 			catch: 接受一个处理函数onRejected作为参数、在rejected时会执行;
	*                 catch的显式返回值会被包装成在个Promise实例中。
	* 			finally: 接受一个任意处理函数作为参数、无论fulfilled或是rejected都会执行
	* @date:2023/4/5
	* ****************************************************************************************************/

// 通过上述原理实现一个简陋的Promise类、用setInterval模拟异步(轮询状态)
class MyPromise {
	/**MyPromsie class
		* @members:
		* 		status: Promise状态机的状态,初始为pending。
		* 		 value: 状态机的状态为fulfilled时,处理的返回值。
		*       reason: 状态机的状态为rejected时,拒绝的原因。
		* @methods:
		* 		constructor(executor):构造函数,executor函数作为实例化参数,该executor的作用是指定Promise状态机的转换规则;
		*                             如状态机在什么时候resolve,并确定fulfilled后应该返回什么值;
		* 							  状态机在什么时候reject,在rejected时,应给出拒绝的原因。
		* 		@instance-methods:
		* 		then(onFulfilled, onRejected):接受两个处理函数onFulfilled、onRejected作为参数。
		* 									  当status为fulfilled时,执行onFulfilled。
		* 									  当status为rejected是,执行onRejected。
		*                                    then的显示返回值会被包装在一个新Promise实例中。
		*     				catch(onRejected):接受一个处理函数onRejected作为参数、在rejected时会执行;
		*                 					  catch的显示返回值会被包装在一个新Promise实例中。
		* 				   finally(onFinally):接受一个任意处理函数作为参数、无论fulfilled或是rejected都会执行,
		* 									  返回值是当前Promise实例。
		*      @static-methods:
		* 			       resolve(value): 生成一个fulfilled的Promise实例。
		*                  reject(reason): 生成一个rejected的Promise实例。
		* 					    all(args): 接受一个Promise实例数组,如果所有Promise实例的状态都为fulfilled,
		*                                 生成一个fulfilled的Promise实例;否则生成一个rejected的Promise实例。
		* 								   这个方法可用于并发执行。
		*                      race(args): 接受一个Promise实例数组,生成一个Promise实例,数组中哪个实例的状态先转变,
		* 								   则生成的实例的状态与先发生状态转变的实例的状态一致。
		* */
	constructor(executor) {
		this.value = undefined;
		this.reason = undefined;
		this.status = 'pending';

		// 定义两个状态转变函数
		const resolve = (value) => {
			if (this.status === 'pending') {
				// 保证状态机的状态转换是不可逆的
				this.status = 'fuifilled';
				this.value = value;
			}
		}
		const reject = (reason) => {
			if (this.status === 'pending') {
				// 保证状态机的状态转换是不可逆的
				this.status = 'rejected';
				this.reason = reason;
			}
		}

		// 执行状态转变规则函数
		executor(resolve, reject);
	}

	catch (onRejected) {
		// catch其实就是一个语法糖
		return this.then(() => {}, onRejected);
	}

	then(onFulfilled, onRejected) {
		const self = this;
		return new MyPromise((resolve, reject) => {
			let exeFn = null; // 回调函数
			let re = null; // 回调函数的返回值, 需要将其包装在一个Promise实例中
			let valueOrReason = null;

			// 使用setInterval轮询Promise状态
			let timer = setInterval(() => {
				if (self.status === 'fuifilled' && typeof onFulfilled === 'function') {
					// fulfilled 状态
					exeFn = onFulfilled;
					valueOrReason = self.value;
				} else if (self.status === 'rejected' && typeof onRejected === 'function') {
					// rejected 状态
					exeFn = onRejected;
					valueOrReason = self.reason;
				}

				// 状态转变
				if (self.status !== 'pending') {
					typeof exeFn === 'function' && (re = exeFn(valueOrReason));
					resolve(re);

					// 清除定时器
					clearInterval(timer);
				}

			});

		})
	}

	finally(fn) {

		// 轮询状态
		let timer = setInterval(() => {

			// 状态转变
			if (this.status !== 'pending') {
				typeof fn === 'function' && fn();

				// 清除定时器
				clearInterval(timer);
			}
		})

		// 返回实例本身
		return this;
	}


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

	static all(args /*Promise array*/ ) {
		const len = args.length;
		const results = []; // 并发处理的结果

		let count = 0; // fulfilled的promise数量 

		return new MyPromise((resolve, reject) => {
			args.forEach(p => {
				p.then((data) => {
					count += 1;
					data && results.push(data);
					if (count === len) {
						resolve(results);
					}
				}, (reason) => {
					reject(reason);
				})
			})
		})
	}
	static race(args /*Promise array*/ ) {
		return new MyPromise((resolve, reject) => {
			args.forEach(p => {
				p.then((value) => {
					resolve(value);
				}, (reason) => {
					reject(reason);
				});
			})
		})
	}
}

const p1 = new MyPromise((resolve, reject) => {
	console.log('begin1');
	setTimeout(() => {
		resolve('fail');
	}, 3000);
	console.log('end1');
});
const p2 = new MyPromise((resolve, reject) => {
	console.log('begin2');
	setTimeout(() => {
		resolve('ok');
	}, 4000)
	console.log('end2');
});
const p3 = new MyPromise((resolve, reject) => {
	console.log('begin3');
	setTimeout(() => {
		resolve('ok');
	})
	console.log('end3');
});

const p = MyPromise.all([p1, p2, p3]);
p.then((val) => {
	console.log(val);
}, (rea) => {
	console.log(rea);
}).finally(() => {
	console.log('over');
}).then(() => {
	console.log('ok');
	console.log(p);
});
console.log(p);
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值