Promise实现

7/19/2022 js

talk is cheap, show me the code

// 定义三种状态
const PENDDING = 'pendding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 处理上个promise返回值
function resolvePromise(promise, value, res, rej) {
	if (promise === value) {
		return rej(new Error('禁止套娃'))
	}
	if (value instanceof Promise) {
		// 异步
		return value.then(res, rej)
	} else {
		// 同步时,下一个promise.status = 'fulfilled'
		res(value)
	}
}
// 执行栈操作
function stackRun(stack, value) {
	while (stack.length) stack.shift()(value)
}
class Promise {
	status = PENDDING
	value = null
	reason = null
	resolveStack = []
	rejectStack = []

	constructor(executor) {
		try {
			executor(this.resolve.bind(this), this.reject.bind(this))
		} catch (e) {
			this.reject.call(this, e)
		}
	}

	resolve(value) {
		if (this.status === PENDDING) {
			this.status = FULFILLED
			this.value = value
			stackRun(this.resolveStack, value)
		}
	}
	reject(reason) {
		if (this.status === PENDDING) {
			this.status = REJECTED
			this.reason = reason
			stackRun(this.rejectStack, reason)
		}
	}
	/**
	 * 通过两个回调拿到上个promise的结果
	 * 方法本身会返回一个新的Promise对象
	 * 如果返回值是promise对象,返回值为成功,新promise就是成功
	 * 如果返回值是promise对象,返回值为失败,新promise就是失败
	 * 如果返回值非promise对象,新promise对象就是成功,值为此返回值
	 */
	then(onRes, onRej) {
		onRes = typeof onRes === 'function' ? onRes : (v) => v // 不传回调默认传递结果下去
		onRej = typeof onRej === 'function' ? onRej : (e) => e
		let self = this
		const promise2 = new Promise((resolve2, reject2) => {
			console.log(this === self)
			// true 注意,由于使用箭头函数,promise内的this都执向上个promise,
			// 因此通过then可以拿到上个promise内部的value,并且通过在then中传入回调函数对value作一些处理,
			// 若上个promise为异步操作,那么会将回调函数存入栈中,等上个promise异步操作完毕之后及时回调
			const onResCb = () => {
				queueMicrotask(() => {
					// 开启微任务,目的是为了在promise2初始化完毕后再拿到它,不然报错
					try {
						let value2 = onRes(this.value)
						resolvePromise(promise2, value2, resolve2, reject2)
					} catch (e) {
						reject2(e)
					}
				})
			}
			const onRejCb = () => {
				queueMicrotask(() => {
					try {
						let reason2 = onRej(this.reason)
						resolvePromise(promise2, reason2, resolve2, reject2)
					} catch (e) {
						reject2(e)
					}
				})
			}
			if (this.status === PENDDING) {
				this.resolveStack.push(onResCb)
				this.rejectStack.push(onRejCb)
			}
			if (this.status === FULFILLED) onResCb()
			if (this.status === REJECTED) onRejCb()
		})
		return promise2
	}
	static resolve(param) {
		// Promise.resolve().then(()=>{...})
		if (param instanceof Promise) return param
		else queueMicrotask(() => new Promise((res) => res(param))) // Promise.resolve()会在返回的Promise外部再包裹一层微任务
	}
	static reject(reason) {
		queueMicrotask(() => new Promise((res, rej) => rej(reason)))
	}
	/**
	 * 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
	 * 如果所有Promise都成功,则返回成功结果数组
	 * 如果有一个Promise失败,则返回这个失败结果
	 */
	static all(promises) {
		return new Promise((resolve, reject) => {
			promises.forEach((promise, index) => {
				// 等所有的promise.resolve结果后将结果按序装入results数组中通过下个promise.resolve传播
				if (promise instanceof Promise)
					promise.then(
						(res) => addData(res, index),
						(e) => reject(e),
					)
				else addData(promise, index)
			})
			let results = []
			let count = 0
			function addData(value, index) {
				results[index] = value
				count++
				if (count === promises.length) resolve(results)
			}
		})
	}
	/**
	 * 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
	 * 返回Promise最快的项,无论成功失败
	 */
	static race(promises) {
		return new Promise((resolve, reject) => {
			promises.forEach((promise, index) => {
				if (promise instanceof Promise)
					promise.then(
						(res) => resolve(res),
						(e) => reject(e),
					)
				else resolve(promise)
			})
		})
	}
	/**
	 * 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
	 * 把每一个Promise的结果,集合成数组,返回
	 */
	static allSettled(promises) {
		return new Promise((resolve, reject) => {
			promises.forEach((promise, index) => {
				;(promise instanceof Promise &&
					promise.then(
						(res) => addData('fulfilled', res, index),
						(e) => addData('rejected', e, index),
					)) ||
					addData('fulfilled', promise, index)
			})
			let results = []
			let count = 0
			function addData(status, value, index) {
				results[index] = { status, value }
				count++
				count === promises.length && resolve(results)
			}
		})
	}
	/**
	 * 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
	 * 如果有一个Promise成功,则返回这个成功结果
	 * 如果所有Promise都失败,则报错
	 */
	static any(promises) {
		return new Promise((resolve, reject) => {
			let count = 0
			promises.forEach((promise) => {
				promise.then(
					(res) => resolve(res),
					(e) => {
						count++
						count === promises.length && reject(new Error('全部GG'))
					},
				)
			})
		})
	}
}

# 参考

1.从一道让我失眠的 Promise 面试题开始,深入分析 Promise 实现细节 (opens new window)

2.Promises/A+规范(中文翻译) (opens new window)

3.看了就会,手写 Promise 原理,最通俗易懂的版本!!! (opens new window)

    我不想谋生,
    我想生活。
    红莲华
    x
    loading...