实现内置Promise

293 阅读1分钟
/*
 * Promise A+:Promise的设计规范(基于原生JS自己可以实现一套内置Promise具备的功能)
 */
class MyPromise {
	constructor(executor) {
		// 初始属性值
		this.status = 'pending';
		this.value = undefined;
		this.resolvedArr = [];
		this.rejectedArr = [];

		// 改变状态的函数
		let changeStatus = (status, result) => {
			if (this.status !== 'pending') return;
			this.status = status;
			this.value = result;
			let arr = status === 'rejected' ? this.rejectedArr : this.resolvedArr;
			arr.forEach(item => (typeof item === 'function' ? item(this.value) : null));
		};
		let resolve = result => {
			if (this.resolvedArr.length > 0) {
				changeStatus('resolved', result);
				return;
			}
			let delayTimer = setTimeout(() => {
				clearTimeout(delayTimer);
				changeStatus('resolved', result);
			}, 0);
		};
		let reject = reason => {
			if (this.rejectedArr.length > 0) {
				changeStatus('rejected', reason);
				return;
			}
			let delayTimer = setTimeout(() => {
				clearTimeout(delayTimer);
				changeStatus('rejected', reason);
			}, 0);
		};

		// 异常捕获处理
		try {
			executor(resolve, reject);
		} catch (error) {
			reject(error);
		}
	}

	then(resolvedFn, rejectedFn) {
		if (typeof resolvedFn !== 'function') {
			resolvedFn = result => {
				return result;
			};
		}
		if (typeof rejectedFn !== 'function') {
			rejectedFn = reason => {
				// throw new Error(reason);
				return new MyPromise((resolve, reject) => {
					reject(reason);
				});
			};
		}

		// then链:返回一个新的Promise实例
		// 1.resolvedArr/rejectedArr不直接存放resolvedFn/rejectedFn,因为要监听这两个方法的返回结果和是否报错(因为只有这样才能控制新实例中到底执行resolve/reject)  =>先存放匿名函数,在匿名函数中把传递的resolvedFn/rejectedFn执行
		// 2.捕获方法执行是否报错
		// 3.方法返回的如果是新的Promise实例,新实例成功或者失败的状态也是我们执行resolve/reject的标准
		return new MyPromise((resolve, reject) => {
			this.resolvedArr.push(() => {
				try {
					let x = resolvedFn(this.value);
					x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
				} catch (error) {
					reject(error);
				}
			});
			this.rejectedArr.push(() => {
				try {
					let x = rejectedFn(this.value);
					x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
				} catch (error) {
					reject(error);
				}
			});
		});
	}

	catch (rejectedFn) {
		// catch(rejectedFn) === then(null,rejectedFn)
		return this.then(null, rejectedFn);
	}

	/* 静态方法 */
	static resolve(result) {
		return new MyPromise(resolve => {
			resolve(result);
		});
	}

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

	static all(arr) {
		return new MyPromise((resolve, reject) => {
			let index = 0,
				results = [];
			for (let i = 0; i < arr.length; i++) {
				let item = arr[i];
				if (!(item instanceof MyPromise)) continue;
				item.then(result => {
					index++;
					results[i] = result;
					if (index === arr.length) {
						resolve(results);
					}
				}).catch(reason => {
					// 只要有一个失败,整体就是失败
					reject(reason);
				});
			}
		});
	}
}
module.exports = MyPromise;