JavaScript 手写 Promise 代码实现

前言:

        相信在工作中各位小伙伴都使用过 Promise,但是它是如何实现的呢,今天就由我来给大家分享一下手写 Promise,及其相关拓展方法的实现,希望对大家有所帮助!

代码:

// proise 三种状态
const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";
function resolvePromise(promise, x, resolve, reject) {
	// x 的值 来决定 走 resolve,还是 reject
	// 需要考虑不同 promise 相互兼容,按照 promiseplus 规范实现,保证兼容性
	if (promise === x) {
		return reject(
			new TypeError("TypeError:Chaining cycle detected for promise !")
		);
	}
	// 判断 x 是不是一个 promise ,如果不是 promise 就直接用这个值,将promise 变为成功态
	if ((typeof x === "object" && x !== null) || typeof x === "function") {
		let called = false;
		try {
			let then = x.then; // 这个x 可能是通过 definproperty 定义的,或者是三方的 promise,这时候我们取then的时候可能会报错!
			if (typeof then === "function") {
				// x.then() // 不要这样写,因为 then 的指向可能发生变化,以第一次获取的为准!
				// x 是一个 promise 用x 的状态决定成功或者失败
				then.call(
					x,
					(y) => {
						if (called) return; // 防止 用户既调用成功,也调用失败,预防三方 promise 没有处理 连续调用 成功 和 失败
						called = true;
						// resolve(y);
						resolvePromise(promise, y, resolve, reject); //递归解析 y 的值
					},
					(r) => {
						if (called) return; // 防止 用户既调用成功,也调用失败,预防三方 promise 没有处理 连续调用 成功 和 失败
						called = true;
						// 一旦失败,不继续解析
						reject(r);
					}
				);
			} else {
				// then 为普通值  {then:123}
				resolve(x);
			}
		} catch (err) {
			if (called) return; // 防止 用户既调用成功,也调用失败,预防三方 promise 没有处理 连续调用 成功 和 失败
			called = true;
			reject(err);
		}
	} else {
		// 不是对象和函数,是普通值
		resolve(x);
	}
}
class Promise {
	constructor(executor) {
		this.status = PENDING; //promise 默认状态
		this.value = undefined; //成功的值
		this.reason = undefined; //失败的原因
		this.onResolveCallBacks = []; //成功回调队列
		this.onRejectCallBacks = []; //失败回调队列
		const resolve = (value) => {
			// 更改成功状态
			if (this.status === PENDING) {
				this.value = value;
				this.status = FULFILLED;
				this.onResolveCallBacks.forEach((cb) => cb(this.value));
			}
		};
		const reject = (reason) => {
			// 更改失败状态
			if (this.status === PENDING) {
				this.reason = reason;
				this.status = REJECTED;
				this.onRejectCallBacks.forEach((cb) => cb(this.reason));
			}
		};
		try {
			executor(resolve, reject); // 执行器方法,立即执行,报错就立刻更改为失败状态
		} catch (e) {
			reject(e);
		}
	}
	then(onFulfilled, onRejected) {
		onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
		onRejected =
			typeof onRejected === "function"
				? onRejected
				: (e) => {
						throw e;
				  };
		// then 方法调用的时候会判断 是执行成功回调还是失败回调
		// 可以 不停的 then 下去
		let p1 = new Promise((resolve, reject) => {
			// x 为 普通值,将x 直接传递给 resovle
			if (this.status === FULFILLED) {
				setTimeout(() => {
					try {
						let x = onFulfilled(this.value);
						resolvePromise(p1, x, resolve, reject);
					} catch (err) {
						reject(err);
					}
				});
			}
			if (this.status === REJECTED) {
				setTimeout(() => {
					try {
						let x = onRejected(this.reason);
						resolvePromise(p1, x, resolve, reject);
					} catch (err) {
						reject(err);
					}
				});
			}
			if (this.status === PENDING) {
				// 发布订阅模式,解决调用 then的时候 proise 状态还没发生改变,将回调存起来,等待状态发生变化的时候统一调用
				this.onResolveCallBacks.push(() => {
					setTimeout(() => {
						try {
							let x = onFulfilled(this.value);
							resolvePromise(p1, x, resolve, reject);
						} catch (err) {
							reject(err);
						}
					});
				});
				this.onRejectCallBacks.push(() => {
					setTimeout(() => {
						try {
							let x = onRejected(this.reason);
							resolvePromise(p1, x, resolve, reject);
						} catch (err) {
							reject(err);
						}
					});
				});
			}
		});
		return p1;
	}
	static resolve(value) {
		if (value instanceof Promise) {
			return value;
		}
		return new Promise((resolve, reject) => {
			resolve(value);
		});
	}
	static reject(value) {
		// if (value instanceof Promise) {
		// 	return value;
		// }
		return new Promise((resolve, reject) => {
			reject(value);
		});
	}
	catch(errCallback) {
		return this.then(null, errCallback);
	}
	static all(promiseList) {
		let result = [];
		let total = 0;
		return new Promise((resolve, reject) => {
			function processResult(data, index) {
				result[index] = data;
				if (++total === promiseList.length) {
					resolve(result);
				}
			}
			promiseList.forEach((item, i) => {
				Promise.resolve(item).then((data) => {
					processResult(data, i);
				}, reject);
			});
		});
	}
	static race(promiseList) {
		return new Promise((resolve, reject) => {
			promiseList.forEach((item, i) => {
				Promise.resolve(item).then(resolve, reject);
			});
		});
	}
	static allSettled(promiseList) {
		let result = [];
		let total = 0;
		return new Promise((resolve, reject) => {
			function processResult(data, index, status) {
				result[index] = { status, value: data };
				if (++total === promiseList.length) {
					resolve(result);
				}
			}
			promiseList.forEach((item, i) => {
				Promise.resolve(item).then(
					(data) => {
						processResult(data, i, "fulfilled");
					},
					(err) => {
						processResult(err, i, "rejected");
					}
				);
			});
		});
	}
	// 无论成功失败都会执行
	finally(finallyCallback) {
		return this.then(
			(data) => {
				return Promise.resolve(finallyCallback()).then(() => data);
			},
			(err) => {
				return Promise.resolve(finallyCallback()).then(() => {
					throw err;
				});
			}
		);
	}
}

function promisify(fn) {
	return function (...args) {
		return new Promise((resolve, reject) => {
			fn(...args, function (err, data) {
				if (err) return reject(err);
				resolve(data);
			});
		});
	};
}


Promise.deferred = function () {
	let dfd = {};
	dfd.promise = new Promise((resolve, reject) => {
		dfd.resolve = resolve;
		dfd.reject = reject;
	});
	return dfd;
};

module.exports = Promise;

功能测试:

        接下来我们需要测试一下上边的代码是否满足 Promise-plus 规范,因此我们使用 官方测试程序进行测试。

        

npm i promises-aplus-tests // 安装测试程序

// promises-aplus-tests 文件名称

promises-aplus-tests myPromise.js

等待程序跑完所有的用例即可展示如上图效果,证明我们写的 Promise 是基本上没问题的!

如有任何问题,请留言或者私信我,我会及时回复大家的问题!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

靖凡无所畏惧

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

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

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

打赏作者

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

抵扣说明:

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

余额充值