面试题:如何手写一个Promise(详细版)

// 1、自己使用javascript手写一个Promise类,
// 2、实现原型方法then/catch/finally,
// 3、实现静态方法resolve/reject。
// 4、实现原型方法all/race

// ES6实现方法
class iPromise {
	constructor(executor) {
		// 存储promise结果
		this.promiseResult = undefined;
		// 存储promise的状态
		this.promiseState = 'pending';
		// 存储所有的回调函数
		this.callbackList = [];

		// resolve方法,将promiseState变为fulfilled,并修改promiseResult
		const resolve = (value) => {
			// 仅在promiseState为pending的时候变化
			if (this.promiseState !== 'pending') return;
			//添加微任务
			queueMicrotask(() => {
				// 将promiseState变为fulfilled
				this.promiseState = 'fulfilled';
				// 将value作为promiseResult
				this.promiseResult = value;
				// 异步执行所有回调函数
				this.callbackList.forEach(cb => cb.onResolved(value));
			});
		}

		// reject方法,将promiseState变为rejected,并修改promiseResult
		const reject = (error) => {
			// 仅在promiseState为pending的时候变化
			if (this.promiseState !== 'pending') return;
			//添加微任务
			queueMicrotask(() => {
				// 将promiseState变为rejected
				this.promiseState = 'rejected';
				// 将error作为promiseResult
				this.promiseResult = error;
				// 异步执行所有回调函数
				this.callbackList.forEach(cb => cb.onRejected(error));
			});
		}
		// 为什么要加try catch 是因为,throw err也相当于调用reject了【前面说过没看过的去补课】
		try {
			/*
			* 同步执行执行器函数
			* 执行器函数接收两个参数,一个是resolve,一个是reject
			*/
			executor(resolve, reject);
		} catch (err) {
			reject(err);
		}

	}

	// 接收两个回调函数作为参数
	then(onResolved, onRejected) {
		//处理异常穿透并且为onResolved,onRejected设置默认值。因为这两个参数可以都不传
		if (typeof onRejected !== 'function') {
			onRejected = err => {
				throw err;
			}
		}
		if (typeof onResolved !== 'function') {
			onResolved = val => val;
		}
		/*
			* 这里必须要写箭头函数,否则this会指向新的Promise对象
			* 进而导致取不到promiseState和promiseResult
			*/
		return new iPromise((resolve, reject) => {
			/*
			* 回调处理函数
			* 这里也请记得用箭头函数,this要穿透几层
			* 箭头函数就用几层
			*/
			const handleCallback = (callback) => {
				try {
					let res = callback(this.promiseResult);
					// 若返回值是promise对象
					if (res instanceof iPromise) {
						res.then(val => resolve(val), err => reject(err));
					} else {
						// 若不是
						resolve(res);
					}
				} catch (error) {
					reject(error);
				}
			}
			// promiseState为fulfilled时调用onResolved
			if (this.promiseState === "fulfilled") {
				setTimeout(() => {
					handleCallback(onResolved);
				});
			}
			// promiseState为rejected时调用onRejected
			if (this.promiseState === "rejected") {
				setTimeout(() => {
					handleCallback(onRejected);
				});
			}
			/*
			* 如果是pending状态,则异步任务,在改变状态的时候去调用回调函数
			* 所以要保存回调函数
			* 因为promise实例可以指定多个回调,于是采用数组 
			*/
			if (this.promiseState === "pending") {
				this.callbackList.push({
					onResolved: () => {
						handleCallback(onResolved)
					},
					onRejected: () => {
						handleCallback(onRejected)
					}
				})
			}
		})
	}

	catch(onRejected) {
		return this.then(undefined, onRejected);
	}
	
	finally(onFinally) {
		//不管成功或者失败都要调用finally
		this.then(() => {
			onFinally()

		}, () => {
			onFinally()

		})
	}

	static resolve(value) {
		return new iPromise((resolve, reject) => {
			if (value instanceof iPromise) {
				value.then(val => resolve(val), err => reject(err));
			} else {
				resolve(value)
			}
		})
	}

	static reject(error) {
		return new iPromise((resolve, reject) => {
			reject(error);
		})
	}

	static all(promiseArrays) {
		return new iPromise((resolve, reject) => {
			// 用以存储执行的结果
			let results = [];
			let length = promiseArrays.length;
			promiseArrays.forEach((promiseObj, index, promiseArrays) => {
				promiseObj.then((val) => {
					results.push(val);
					// 由于是多个异步任务的关系,需要判断是否都执行完毕
					if (results.length === length) {
						resolve(results);
					}
				}, err => {
					// 如有错误,则reject
					reject(err);
				});
			})
		})
	}

	static race(promiseArrays) {
		return new iPromise((resolve, reject) => {
			promiseArrays.forEach(promiseObj => {
				promiseObj.then(val => {
					resolve(val);
				}, err => {
					reject(err);
				});
			});
		})
	}
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值