Promise源码实现

ECMAscript 6 原生提供了 Promise 对象,用来优雅解决异步问题,避免回调噩梦。

Promise对象有三种状态:

  • pending: 初始状态,不是成功或失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。

实现Promise:

目标:可以实现优雅的异步处理方式,以下是想要达到最终状态:

new MyPromise(function(resolve){
	setTimeout(()=>{
		resolve(122121)
	},1000)
}).then(r=>{
	console.log(r)
}).catch(e=>{
	console.log(e)
})

第一步:定义状态,初始化Promise外壳

  • 定义三种状态常量、增加判断是否为函数方法(Promise参数必须是函数)
  • 初始化状态、返回值、成功或失败队列
  • 初始化then、catch、resolve、reject、all、race、finally方法(简易Promise只需then和catch即可)
// 判断变量否为function
const isFunction = variable => typeof variable === 'function'
// 定义Promise的三种状态常量
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class MyPromise {
	constructor (handle) {
		if (!isFunction(handle)) {
			throw new Error('MyPromise must accept a function as a parameter')
		}
		// 初始化状态
		this._status = PENDING
        // 初始化返回值
        this._value = undefined
		// 初始化成功回调函数队列
		this._fulfilledQueues = []
		// 初始化失败回调函数队列
		this._rejectedQueues = []
        // todo
	}
	then (onFulfilled, onRejected) {
		// todo
	}
	// 添加catch方法
	catch (onRejected) {
		// todo
	}
	// 添加静态resolve方法
	static resolve (value) {
		// todo
	}
	// 添加静态reject方法
	static reject (value) {
		// todo
	}
	// 添加静态all方法
	static all (list) {
		// todo
	}
	// 添加静态race方法
	static race (list) {
		// todo
	}
	finally (cb) {
		// todo
	}
}

第二步:实现传递参数resolve和reject

  • 执行回调函数handle方法,并传入resolve和reject方法,方便回调函数传值
  • 了解resolve、reject方法,在传入的函数中,resolve可以把promise的状态改为FULFILLED,reject改为REJECTED
// 判断变量否为function
const isFunction = variable => typeof variable === 'function'
// 定义Promise的三种状态常量
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class MyPromise {
	constructor (handle) {
		if (!isFunction(handle)) {
			throw new Error('MyPromise must accept a function as a parameter')
		}
		// 初始化状态
		this._status = PENDING
        // 初始化返回值
        this._value = undefined
		// 初始化成功回调函数队列
		this._fulfilledQueues = []
		// 初始化失败回调函数队列
		this._rejectedQueues = []
        // 执行回调函数handle
        try {
			handle(this._resolve.bind(this), this._reject.bind(this)) 
		} catch (err) {
			this._reject(err)
		}
	}
}

resolve函数待办项

  • 修改PENDING状态为FULFILLED状态
  • 执行成功队列的函数
  • 赋值this._value -- resolve函数传递的值
    _resolve (val) {
		if (this._status !== PENDING) return
		this._status = FULFILLED
		// 依次执行成功队列中的函数,并清空队列
		const runFulfilled = (value) => {
			let cb;
			while (cb = this._fulfilledQueues.shift()) {
				cb(value)
			}
		}
		this._value = val
		runFulfilled(val)
	}

resolve函数优化:

  • 支持同步Promise
  • 支持链式调用
    _resolve (val) {
    	const run = () => {
			if (this._status !== PENDING) return
			this._status = FULFILLED
			// 依次执行成功队列中的函数,并清空队列
			const runFulfilled = (value) => {
				let cb;
				while (cb = this._fulfilledQueues.shift()) {
					cb(value)
				}
			}
			// 依次执行失败队列中的函数,并清空队列
			const runRejected = (error) => {
				let cb;
				while (cb = this._rejectedQueues.shift()) {
					cb(error)
				}
			}
			/* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,
				当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态
			*/
			if (val instanceof MyPromise) {
				val.then(value => {
					this._value = value
					runFulfilled(value)
				}, err => {
					this._value = err
					runRejected(err)
				})
			} else {
				this._value = val
				runFulfilled(val)
			}
		}
		// 为了支持同步的Promise,这里采用异步调用
		setTimeout(run, 0)
	}

reject函数待办项

  • 修改PENDING状态为REJECTED状态
  • 执行失败队列的函数
  • 赋值this._value -- reject函数传递的值
    _reject (err) { 
		if (this._status !== PENDING) return
		// 依次执行失败队列中的函数,并清空队列
		const run = () => {
			this._status = REJECTED
			this._value = err
			let cb;
			while (cb = this._rejectedQueues.shift()) {
				cb(err)
			}
		}
		// 为了支持同步的Promise,这里采用异步调用
		setTimeout(run, 0)
	}

then函数待办项

  • 当状态为pengding时,将then方法加入执行队列等待执行
  • 当状态已经改变时,立即执行对应的回调函数
then (onFulfilled, onRejected) {
	const { _value, _status } = this
	// 返回一个新的Promise对象
	return new MyPromise((onFulfilledNext, onRejectedNext) => {
		// 封装一个成功时执行的函数
		let fulfilled = value => {
			try {
				if (!isFunction(onFulfilled)) {
					onFulfilledNext(value)
				} else {
					let res =  onFulfilled(value);
					if (res instanceof MyPromise) {
						// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
						res.then(onFulfilledNext, onRejectedNext)
					} else {
						//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
						onFulfilledNext(res)
					}
				}
			} catch (err) {
				// 如果函数执行出错,新的Promise对象的状态为失败
				onRejectedNext(err)
			}
		}
		// 封装一个失败时执行的函数
		let rejected = error => {
			try {
				if (!isFunction(onRejected)) {
					onRejectedNext(error)
				} else {
						let res = onRejected(error);
						if (res instanceof MyPromise) {
							// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
							res.then(onFulfilledNext, onRejectedNext)
						} else {
							//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
							onFulfilledNext(res)
						}
				}
			} catch (err) {
				// 如果函数执行出错,新的Promise对象的状态为失败
				onRejectedNext(err)
			}
		}
		switch (_status) {
			// 当状态为pending时,将then方法回调函数加入执行队列等待执行
			case PENDING:
				this._fulfilledQueues.push(fulfilled)
				this._rejectedQueues.push(rejected)
				break
			// 当状态已经改变时,立即执行对应的回调函数
			case FULFILLED:
				fulfilled(_value)
				break
			case REJECTED:
				rejected(_value)
				break
		}
	})
}

其他函数实现起来比较简单,其实就是各种语法糖。

catch函数:

  • 直接指向then的第二个方法
catch (onRejected) {
	return this.then(undefined, onRejected)
}

resolve函数 

  • new Promise((resolve)=>resolve())的语法糖
static resolve (value) {
	// 如果参数是MyPromise实例,直接返回这个实例
	if (value instanceof MyPromise) return value
	return new MyPromise(resolve => resolve(value))
}

reject函数

  • new Promise((resolve, reject)=>reject())的语法糖
static reject (value) {
	return new MyPromise((resolve ,reject) => reject(value))
}

all函数

  • 所有Promise都完成执行函数
    static all (list) {
		return new MyPromise((resolve, reject) => {
			/**
			 * 返回值的集合
			 */
			let values = []
			let count = 0
			for (let [i, p] of list.entries()) {
				// 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
				this.resolve(p).then(res => {
					values[i] = res
					count++
					// 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
					if (count === list.length) resolve(values)
				}, err => {
					// 有一个被rejected时返回的MyPromise状态就变成rejected
					reject(err)
				})
			}
		})
	}

race函数

  • 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
    static race (list) {
		return new MyPromise((resolve, reject) => {
			for (let p of list) {
				// 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
				this.resolve(p).then(res => {
					resolve(res)
				}, err => {
					reject(err)
				})
			}
		})
	}

finally函数

  • 无论成功或失败都会执行的函数 
finally (cb) {
	return this.then(
		value  => MyPromise.resolve(cb()).then(() => value),
		reason => MyPromise.resolve(cb()).then(() => { throw reason })
	);
}

完整源码:

// 判断变量否为function
const isFunction = variable => typeof variable === 'function'
// 定义Promise的三种状态常量
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

class MyPromise {
	constructor (handle) {
		if (!isFunction(handle)) {
			throw new Error('MyPromise must accept a function as a parameter')
		}
		// 添加状态
		this._status = PENDING
		// 添加状态
		this._value = undefined
		// 添加成功回调函数队列
		this._fulfilledQueues = []
		// 添加失败回调函数队列
		this._rejectedQueues = []
		// 执行handle
		try {
			handle(this._resolve.bind(this), this._reject.bind(this)) 
		} catch (err) {
			this._reject(err)
		}
	}
	// 添加resovle时执行的函数
	_resolve (val) {
		const run = () => {
			if (this._status !== PENDING) return
			this._status = FULFILLED
			// 依次执行成功队列中的函数,并清空队列
			const runFulfilled = (value) => {
				let cb;
				while (cb = this._fulfilledQueues.shift()) {
					cb(value)
				}
			}
			// 依次执行失败队列中的函数,并清空队列
			const runRejected = (error) => {
				let cb;
				while (cb = this._rejectedQueues.shift()) {
					cb(error)
				}
			}
			/* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,
				当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态
			*/
			if (val instanceof MyPromise) {
				val.then(value => {
					this._value = value
					runFulfilled(value)
				}, err => {
					this._value = err
					runRejected(err)
				})
			} else {
				this._value = val
				runFulfilled(val)
			}
		}
		// 为了支持同步的Promise,这里采用异步调用
		setTimeout(run, 0)
	}
	// 添加reject时执行的函数
	_reject (err) { 
		if (this._status !== PENDING) return
		// 依次执行失败队列中的函数,并清空队列
		const run = () => {
			this._status = REJECTED
			this._value = err
			let cb;
			while (cb = this._rejectedQueues.shift()) {
				cb(err)
			}
		}
		// 为了支持同步的Promise,这里采用异步调用
		setTimeout(run, 0)
	}
	// 添加then方法
	then (onFulfilled, onRejected) {
		const { _value, _status } = this
		// 返回一个新的Promise对象
		return new MyPromise((onFulfilledNext, onRejectedNext) => {
			// 封装一个成功时执行的函数
			let fulfilled = value => {
				try {
					if (!isFunction(onFulfilled)) {
						onFulfilledNext(value)
					} else {
						let res =  onFulfilled(value);
						if (res instanceof MyPromise) {
							// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
							res.then(onFulfilledNext, onRejectedNext)
						} else {
							//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
							onFulfilledNext(res)
						}
					}
				} catch (err) {
					// 如果函数执行出错,新的Promise对象的状态为失败
					onRejectedNext(err)
				}
			}
			// 封装一个失败时执行的函数
			let rejected = error => {
				try {
					if (!isFunction(onRejected)) {
						onRejectedNext(error)
					} else {
							let res = onRejected(error);
							if (res instanceof MyPromise) {
								// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
								res.then(onFulfilledNext, onRejectedNext)
							} else {
								//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
								onFulfilledNext(res)
							}
					}
				} catch (err) {
					// 如果函数执行出错,新的Promise对象的状态为失败
					onRejectedNext(err)
				}
			}
			switch (_status) {
				// 当状态为pending时,将then方法回调函数加入执行队列等待执行
				case PENDING:
					this._fulfilledQueues.push(fulfilled)
					this._rejectedQueues.push(rejected)
					break
				// 当状态已经改变时,立即执行对应的回调函数
				case FULFILLED:
					fulfilled(_value)
					break
				case REJECTED:
					rejected(_value)
					break
			}
		})
	}
	// 添加catch方法
	catch (onRejected) {
		return this.then(undefined, onRejected)
	}
	// 添加静态resolve方法
	static resolve (value) {
		// 如果参数是MyPromise实例,直接返回这个实例
		if (value instanceof MyPromise) return value
		return new MyPromise(resolve => resolve(value))
	}
	// 添加静态reject方法
	static reject (value) {
		return new MyPromise((resolve ,reject) => reject(value))
	}
	// 添加静态all方法
	static all (list) {
		return new MyPromise((resolve, reject) => {
			/**
			 * 返回值的集合
			 */
			let values = []
			let count = 0
			for (let [i, p] of list.entries()) {
				// 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
				this.resolve(p).then(res => {
					values[i] = res
					count++
					// 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
					if (count === list.length) resolve(values)
				}, err => {
					// 有一个被rejected时返回的MyPromise状态就变成rejected
					reject(err)
				})
			}
		})
	}
	// 添加静态race方法
	static race (list) {
		return new MyPromise((resolve, reject) => {
			for (let p of list) {
				// 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
				this.resolve(p).then(res => {
					resolve(res)
				}, err => {
					reject(err)
				})
			}
		})
	}
	finally (cb) {
		return this.then(
			value  => MyPromise.resolve(cb()).then(() => value),
			reason => MyPromise.resolve(cb()).then(() => { throw reason })
		);
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值