js手写方法之--Promise

js手写方法之–Promise

Promiseasync/await是ES6中常用的异步操作方法,为了深刻理解Promise的用法,解读源码是一个很好的方案。其核心方法是Promise构造函数,以及.then方法,其他静态方法都是在此基础之上封装的
为了方便理解,以下代码经过了适当删减

// Promise状态常量值
// 状态还未变化
const PENDING = 0
// 成功
const FULLFILLED = 1
// 失败
const REJECTED = 2
function MyPromise (executor) {
	// 初始状态,0
	this.state = PENDING
	// 状态成功时的值,初始为 undefined
	this.value = undefined
	// 状态失败时的值,初始为 undefined
	this.reason = undefined
	
	// 异步时,成功的回调;同步任务时为空
	// 也可以这么理解:
	// 异步方法时,先.then将回调推入this.onResolvedCallbacks; 再resolve更改状态 并执行回调
	// 同步方法时,先resolve更改状态,再.then执行回调
	this.onResolvedCallbacks = []
	// 异步时,失败的回调;同步任务时为空
	this.onRejectedCallbacks = []
	
	// executor 中执行resolve的方法
	const resolve = (result) => {
		// 状态一旦改变,就不能再改变了
		if (this.state === PENDING) {
			this.state = FULLFILLED
			this.value = result
			this.onResolvedCallbacks.forEach(cb => { cb() })
		}
	}
	const reject = (error) => {
		// 状态一旦改变,就不能再改变了
		if (this.state === PENDING) {
			this.state = REJECTED
			this.value = error
			this.onRejectedCallbacks.forEach(cb => { cb() })
		}
	}
	try {
		// excutor 是用户传来的执行器
		// 即 new Promise(function(resolve, reject) {}) 中的function
		// 从这里也能看出 excutor 是同步执行
		excutor(resolve, reject)
	} catch (e) {
		reject(e)
	}
}

接下来是添加原型链方法.then

// 构造器建好后,添加原型链方法
MyPromise.prototype = {
	constructor: MyPromise,
	// then接受两个参数,一个是成功方法,一个是失败方法
	then: function (onResolved, OnRejected) {
		// 如果成功方法不存在,他就是一个返回当前值的方法
		onResolved = onResolved ? onResolved : result => result
		// 如果失败方法不存在,他就是一个把当前信息当成错误抛出的方法
		onRejected = onRejected ? onRejected : err => { throw err}
		
		/**
		 * Promise支持.then().then()这种链式调用,所以then()的返回值也应是一个Promise对象
		 * 由于Promise存在前面的then执行成功,后面的then执行失败的情况
		 * 所以不能返回当前状态已经固定的this,而是返回一个新的Promise
		 */
		let p2 = new Promise((resolve, reject) => {
			// 根据当前promise的状态判断是否执行回调
			if (this.state === FULLFILLED) {
				// 执行了 resolve(result),状态成功,this.value = result
				let result
				if (isPromise(this.value)) {
					// this.value是一个Promise,那么result也是一个promise
					result = this.value.then(onResolved, onRejected)
				} else {
					// 此时result可能是普通对象,也可能是promise
					result = onResolved(this.value)
				}
				// 对result进行解析,直到最终执行resolve(obj)或reject(err)
				// obj为result最后返回的那个对象
				resolvePromise(result, resolve, reject)
			}
			
			if (this.state === REJECTED) {
				// 执行了reject(error),状态失败,this.reason = error
				let error
				if (isPromise(this.reason)) {
					error = this.reason.then(onResolved, onRejected)
				} else {
					error = onRejected(this.reason)
				}
				// 对error进行解析,直到最终执行reject(err)
				resolvePromise(error, resolve, reject)
			}
			
			if (this.state === PENDING) {
				// 异步方法,执行器excutor中还未执行到resolve,于是将回调推入回调数组中
				this.onResolvedCallbacks.push(() => {
					if (isPromise(this.value)) {
						result = this.value.then(onResolved, OnRejected )
					} else {
						result = onResolved(this.value)
					}
					resolvePromise(result, resolve, reject)
				})
				this.onRejectedCallbacks.push(() => {
					let error
					if (isPromise(this.reason)) {
						error= this.reason.then(onResolved, OnRejected )
					} else {
						error= onRejected(this.reason)
					}
					resolvePromise(error, resolve, reject)
				})
			}
		})
		return p2
	}
}
/**
 * 判断一个对象是否为Promise对象
 * 判断他是否拥有then方法
 */
function isPromise (obj) {
	if ((typeof obj === 'object' && obj !== null) || typeof obj === 'function') {
		if (typeof obj.then === 'function') {
			return true
		}
	}
	return false
}
// 这个方法的目的,是解析result中的data
// 并最终执行外层p2的resolve或reject方法
function resolvePromise (result, resolve, reject) {
	if (isPromise(result)) {
		// 因为then内部新建了一个promise,所以这里需要判断result是否执行过了
		let called = false
		try {
			let then = result.then
			// 这里 then.call(result, r=>{}, j=>{})
			then.call(result, r => {
				if (called) return
				called = true
				resolvePromise(r, resolve, reject)
			}, j => {
				if (called) return
				called = true
				resolvePromise(j, resolve, reject)
			})
		} catch (e) {
			if (called) return
			called = true
			reject(e)
		}
	} else {
		// result是基本对象,直接resolve
		resolve(result)
	}
}

其他Promise方法

其他Promise方法都是上述的一个封装
MyPromise.prototype.catch(errorFn)

MyPromise.prototype.catch = function (errorFn) {
	return this.then(null, errorFn)
}

MyPromise.resolve(data)

MyPromise.resolve = function (data) {
	return new MyPromise((resolve, reject) => {
		resolve(data)
	})
}

MyPromise.reject(error)

MyPromise.reject= function (error) {
	return new MyPromise((resolve, reject) => {
		reject(error)
	})
}

MyPromise.all([...promiseObj])

/**
 * 所有promise执行成功后,返回整个列表
 * 如果有失败的,返回最先失败的结果
 */
MyPromise.all= function (promiseObj = []) {
	return new Promise((resolve, reject) => {
		let result = []
		// 记录总数量,每成功一次减一
		let index = allPromise.length
		for (let i = 0; i < promiseObj.length; i++) {
			let p = promiseObj[i]
			if (isPromise(p)) {
				p.then(data => {
					result[i] = data
					// 异步成功后才减去index
					index--
					if (index === 0) {
						resolve(result)
					}
				}).catch(err => {
					// 任何一个异步失败都抛出错误
					reject(err)
				})
			} else {
				result[i] = p
				// 非promise对象,直接减一
				index--
			}
		}
		// 如果没有异步数据
		if (index === 0) {
			resolve(result)
		}
	})
}

MyPromise.race([...promiseObj])

/**
 * 谁先执行完成返回谁,不管是成功还是失败
 */
MyPromise.race = function (promiseObj= []) {
	return new Promise((resolve, reject) => {
		for (let i = 0; i < promiseObj.length; i++) {
			let p = promiseObj[i]
			if (isPromise(p)) {
				p.then(resolve).catch(reject)
			} else {
				resolve(p)
			}
		}
	})
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值