Promise源码实现

106 阅读2分钟

前言

js执行单线程,而前端异步的实现实则为一个循环回调; Eventloop中异步任务区分了宏任务(如:setTimeout、setInterval、script)和微任务(如:process.nextTick、Promise、MutationObserver)

promise的实现实际上有点类似于这种eventloop,其循环return自身,每个then产生一层的promise,每层有专属的status状态,_nextResolveQueue保存的调用下一层级resolve的执行函数,以此从第一层promise执行完成回调resolve到后面一层一层的resolve回调到结束

思路

  • 定义promise时,new Promise(function(res, rej){res()}).then(function(data){return new Promise()}).then(()=>{})
  • _status promise实例初始化时候为pending,当该实例执行到_resolve函数后状态变为fulling
  • _value 当每一层执行_resolve时会接收上一层级传过来的return值
  • _nextResolveQueue存放下一层级对.then第一个参数nextResolveHandle函数的包装函数, 绑定该层级的resolve执行后便会遍历对_nextResolveQueue所有函数的执行
  • 构造Promise函数时会传参数handle函数,并且立即执行,在其中会传入resolve参数,resolve的执行便会执行由.then参数组成的包装函数
  • 包装函数执行后分两种情况,一返回真实的值,则直接执行下一层级的resolve并传入刚返回的真实值 ;二返回新的Promise实例,此时实例调用.then在此处生成新的promise层级,并将下层级的resolve函数放入.then第一个参数即nextResolveHandle;
const isFunction = varible => typeof varible === 'function'
function MyPromise(handle) {
	this._status = 'pending'
	this._value = ''
	this._error = ''
	this._nextResolveQueue = []
	this._nextRejectQueue = []
	try {
		handle(this._resolve.bind(this), this._reject.bind(this))
	} catch(e) {
		console.log(e);
	}
}

MyPromise._catchCallback = null;

MyPromise.prototype.then = function(nextResolveHandle, nextRejectHandle) {
	let { _value, _error, _status, _nextResolveQueue, _nextRejectQueue } = this
	return new MyPromise(function(nextResolve, nextReject) { 
		const resolveFn = function(value) {
			try {
				if(!isFunction(nextResolveHandle)) {
					nextResolve(value)
				} else {
					let result = nextResolveHandle(value)
					if(result instanceof MyPromise) {
						result.then(nextResolve, nextReject)
					} else {
						nextResolve(result)
					}
				}
			} catch(e) {
				MyPromise._catchCallback && MyPromise._catchCallback(e)
			}
		}
		const rejectFn = function(error) {
			try {
				if(!isFunction(nextRejectHandle)) {
					nextReject(error)
				} else {
					let result = nextRejectHandle(error)
					if(result instanceof MyPromise) {
						result.then(nextResolve, nextReject)
					} else {
						nextReject(result)
					}
				}
			} catch(e) {
				MyPromise._catchCallback && MyPromise._catchCallback(e)
			}
		}

		switch (_status) {
			case 'pending':
				// 待办等待resolve的执行,先存放待执行handle到queue中
				_nextResolveQueue.push(resolveFn);
				_nextRejectQueue.push(rejectFn);
				break;
			case 'fulling':
				// 已经处理完,即没有等待直接resolve了
				resolveFn(_value);
				break;
			case 'rejected': 
				// 还没执行完, 出现错误
				rejectFn(_error)
				break;
		}
	})
}

MyPromise.prototype.catch = function(handle) {
	MyPromise._catchCallback = handle
}

MyPromise.prototype._resolve = function(data) {
	let { _value, _status, _nextResolveQueue } = this
	if(_status === 'fulling') return
	const run = function() {
		_status = 'fulling'
		_value = data
		let cb;
		while(cb = _nextResolveQueue.shift()) {
			cb(_value)
		}
	}
	setTimeout(function(){
		run()
	})
}

MyPromise.prototype._reject = function(data) {
	let { _error, _status, _nextRejectQueue } = this
	if(_status === 'rejected') return
	const run = function() {
		_status = 'rejected'
		_error = data
		let cb;
		while(cb = _nextRejectQueue.shift()) {
			cb(_error)
		}
	}
	setTimeout(function(){
		run()
	})
}