Promise的简单实现

JS中Promise的简单实现

什么是Promise

简单点来说就是异步,存在的意义在于将多级嵌套的异步调用(回调地狱)变为链式结构来处理,这篇博文主要说一个自己的简单实现思路。(有不对的请指正)

Promise简单实例

下面是一个简单的Promise实例

new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve(2333)
	}, 2000)
}).then(res => {
	console.log(res)
})

分析

  • Promise的构造函数参数为一个包含两个参数的函数,即function fn(resolve, reject) {}
  • Promise有一个then方法,then方法的参数是两个函数,在js中即 Promise.prototype = function then(resCallback, errCallback){}
  • Promise 需要有一个变量去保存resolve(val)或者reject(val)中调用的参数val
  • Promise本身有三个状态pending、fulfilled、rejected,需要有一个变量_status去储存状态(pending表示正在等待调用,fulfilled表示调用成功,rejected表示调用失败,主要为了在then方法中判断应该调用哪种回调函数)

可以看出Promise的本质实际是个回调函数,下面一步一步来分析Promise的内部基本构造

// 构造函数
// fn :  function fn(resolve, reject){ ...some code }
function _promise(fn) {
	let _self = this;
	this._value; // undefined 保存resolve(val)或者reject(val)中调用的参数val
	this._status = "pending"; // 保存promise的状态
	let _resolve = function(val) {
		if(_self._status !== "pending") return; // promise的状态是单向的
		_self._status = "fulfilled"; //调用_resolve表示操作成功
		_self._value = val;        // 保存val 方便在then中调用
	}
	let _reject = function(val) {
		if(_self._status !== "pending") return; // promise的状态是单向的
		_self._status = "rejected"; //调用_reject表示操作失败
		_self._value = val;
	}
	fn(_resolve, _reject);   //回调
}
_promise.prototype.then = function (onFulfilled, onRejected){
	onFulfilled && onFulfilled(this._value);
	onRejected && onRejected(this._value);
}

new _promise((resolve, reject) => {
	resolve(2333);
}).then(res => {
	console.log("这里是自定义_promise:", res);
})

基本思路上面的已经完成,但是还有两个大问题:

  • 不支持链式调用(因为_promise中只定义了一个_value,只支持then方法中处理一次回调)
  • 没有实现异步功能

基本功能实现(为链式调用的实现做准备)

定义两个数组onResolvedCallbackonRejectedCallback来存放所有then中的回调函数,在then中将回调函数保存在数组中,那在什么时候调用呢?仔细想想,其实onResolvedCallbackonRejectedCallback是在_resolve/_reject后调用的,于是思路清晰了,先在then中定义一个回调函数,然后在_resolve/_reject中进行调用。

function _promise(fn) {
	let _self = this;
	this._value; 
	this._status = "pending"; 
	
	/-- 增加两个变量来存放then中的callback --/
	this.onResolvedCallback = [];
	this.onRejectedCallback = [];
	
	let _resolve = function(val) {
		if(_self._status !== "pending") return;
		_self._status = "fulfilled";
		_self._value = val;
		/-- 在这里调用callback,不管后面的链式调用中有多少个then,这里都是按顺序执行 --/
		for(let i=0; i<_self.onResolvedCallback.length; i++) {
			_self.onResolvedCallback[i](val);
		}
	}
	let _reject = function(val) {
		if(_self._status !== "pending") return;
		_self._status = "rejected"; 
		_self._value = val;
		/-- onRejectCallback同理 --/
		for(let i=0; i<_self.onRejectedCallback.length; i++) {
			_self.onRejectedCallback[i](val);
		}
	}
	
	fn(_resolve, _reject);  
}
_promise.prototype.then = function (onFulfilled, onRejected) {
	//onFulfilled && onFulfilled(this._value);
	//onRejected && onRejected(this._value);
	/-- 这里不直接调用回调函数了,而是将回调函数保存在数组中 --/
	this.onResolvedCallback.push(onFulfilled);
	this.onRejectedCallback.push(onRejected);
}

let promise1 = new _promise((resolve, reject) => {
	resolve("没有设置延迟的resolve");
}).then(res => {
	console.log("这里是自定义_promise:", res);   // 没有打印内容
})

let promise2 = new _promise((resolve, reject) => {
	 setTimeout(() => {
	 	resolve("设置延迟了哦");              
	 }, 2000)
}).then(res => {
	console.log("这里是自定义_promise:", res);  // 打印出 “这里是自定义_promise: 设置延迟了哦”
})

在这里插入图片描述
上面的思路有了,但是实际上代码运行是有问题的,,链式调用解决了,但是异步的问题没解决,大家想想上面的逻辑

  1. 先将then中定义的函数保存在数组里
  2. _resolve_reject运行结束后调用callback
  3. promise1没有设置延迟,callback没有成功调用。promise2设置延迟,callback成功调用
    道理其实很简单,按照我们的设计,应该是先将callback加入到数组中,然后再进行函数调用的,所以应该为_resolve_reject添加setTimeout
function _promise(fn) {
	let _self = this;
	this._value; 
	this._status = "pending"; 
	
	this.onResolvedCallback = [];
	this.onRejectedCallback = [];
	
	let _resolve = function(val) {
		/-- 保证then中的callback先定义再使用 --/
		setTimeout(() => {
			if(_self._status !== "pending") return;
			_self._status = "fulfilled";
			_self._value = val;
			for(let i=0; i<_self.onResolvedCallback.length; i++) {
				_self.onResolvedCallback[i](val);
			}
		})
	}
	let _reject = function(val) {
		/-- 保证then中的callback先定义再使用 --/
		setTimeout(() => {
			if(_self._status !== "pending") return;
			_self._status = "rejected"; 
			_self._value = val;
			for(let i=0; i<_self.onRejectedCallback.length; i++) {
				_self.onRejectedCallback[i](val);
			}
		})
	}
	/-- 我相信你一定能看懂这里加入的try --/
	try {
		fn(_resolve, _reject);
	} catch(err) {
		_reject(err);
	}
}
_promise.prototype.then = function (onFulfilled, onRejected) {
	this.onResolvedCallback.push(onFulfilled);
	this.onRejectedCallback.push(onRejected);
}

let promise1 = new _promise((resolve, reject) => {
	resolve("没有设置延迟的resolve");
}).then(res => {
	console.log("这里是自定义_promise:", res);   // 打印出 “没有设置延迟的resolve”
})

let promise2 = new _promise((resolve, reject) => {
	 setTimeout(() => {
	 	resolve("设置延迟了哦");              
	 }, 2000)
}).then(res => {
	console.log("这里是自定义_promise:", res);  // 打印出 “这里是自定义_promise: 设置延迟了哦”
})

在这里插入图片描述
到这里一个基本功能已经完成,本瓜皮语死早,不知道上面的代码有没有表达清楚我的意思,如果看到这里可以理解我的意思,那么恭喜你Promise的基本原理你已经掌握了,下面可以对代码再进行一点优化。

完善then方法

个人认为是对Promise原理的理解中比较重要的一部分
先来观察一下Promise中的then方法,Promise是为了解决回调地狱而存在的,假如现在有若干个异步任务,即:job1.then(job2).then(job3)…catch(handleError);

  1. job1成功才能继续job2…
  2. job1、job2和job3都是Promise
  3. 如果其中有任何一个任务失败则不再继续并执行错误处理函数(catch方法)

先贴一个Promise链式调用的例子

let multiply = function(input) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve(input * input);
		}, 500)
	})
}
let add = function(input) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve(input + input);
		}, 500)
	})
}

let p = new Promise((resolve, reject) => {
	resolve(1);
})
p.then(multiply)
 .then(add)
 .then(res => {
	console.log("结果是:", res);
})

分析(重要)

  • then方法返回的是一个Promise
// ...省略一些代码
_promise.prototype.then = function(onFulfilled, onRejected) {
	let _self = this;
	return new Promise((resolve, reject) => {
		_self.onResolvedCallback.push((val) => {
			onFulFilled(val);
		})
	})
}
  • 如果在then方法中return,要保证可以链式调用
// ...省略一些代码
_promise.prototype.then = function(onFulfilled, onRejected) {
	let _self = this;
	return new _promise((resolve, reject) => {
		_self.onResolvedCallback.push((val) => {
			let x = onFulfilled(val);  // 如果then中return,则x有值
			resolve(x);
		})
	})
}

new _promise((resolve, reject) => {
	resolve(123);
}).then(res => {
	return res + 20;
}).then(res => {
	console.log(res);                     // 输出: 143
	return new _promise((resolve, reject) => {
		resolve(res + 20);
	})
}).then(res => {
	console.log(res);   // 输出:_promise{_status: 'fulfilled', onResolvedCallback: [], onRejectedCallback: [], _value: 163}
})

Promise的简单实现_第1张图片

  • 但如果x是一个Promise呢,就不能直接resolve了,需要添加判定条件并进行处理
  • 如果x是一个Promise,我们需要获取x的resolve或者reject的参数
  • 通过x.then(resolve, reject),将外层_promiseresolvereject作为onFulfilledonRejected传递到内层_promise
// ...省略一些代码
_promise.prototype.then = function(onFulfilled, onRejected) {
	let _self = this;
	return new _promise((resolve, reject) => {
		_self.onResolvedCallback.push((val) => {
			let x = onFulfilled(val); 
			// 判断x的类型
			if(x instanceof _promise) {
				x.then(resolve, reject);
			} else {
				resolve(x);
			}
		})
	})
}

new _promise((resolve, reject) => {
	resolve(123);
}).then(res => {
	return res + 20;
}).then(res => {
	console.log(res);                     // 输出: 143
	return new _promise((resolve, reject) => {
		resolve(res + 20);
	})
}).then(res => {
	console.log(res);   // 输出163
})

在这里插入图片描述
这样_promise的链式调用也完成了,最后完善一下(做一下reject的处理),完整代码如下,下面代码只是一个Promise的基本原理的实现,实际的Promise还需要做一些代码健壮性处理(比如try catch),
还有一些Promise的方法,如:

  • _promise.ptorotype.catch()
  • _promise.ptorotype.finally()
  • _promise.all()
  • _promise.race()

感兴趣的可以自己尝试写一下,再阅读源码看看自己写的有哪些不足

function _promise(fn) {
	let _self = this;
	this._value; 
	this._status = "pending"; 
	
	this.onResolvedCallback = [];
	this.onRejectedCallback = [];
	
	let _resolve = function(val) {
		setTimeout(() => {
			if(_self._status !== "pending") return;
			_self._status = "fulfilled";
			_self._value = val;
			for(let i=0; i<_self.onResolvedCallback.length; i++) {
				_self.onResolvedCallback[i](val);
			}
		})
	}
	let _reject = function(val) {
		setTimeout(() => {
			if(_self._status !== "pending") return;
			_self._status = "rejected"; 
			_self._value = val;
			for(let i=0; i<_self.onRejectedCallback.length; i++) {
				_self.onRejectedCallback[i](val);
			}
		})
	}
	try {
		fn(_resolve, _reject);
	} catch(err) {
		_reject(err);
	}
}
/**
@params function, function
@return _promise
**/
_promise.prototype.then = function(onFulfilled, onRejected) {
	let _self = this;
	return new _promise((resolve, reject) => {
		_self.onResolvedCallback.push((val) => {
			let x = onFulfilled(val); 
			// 判断x的类型
			if(x instanceof _promise) {
				x.then(resolve, reject);
			} else {
				resolve(x);
			}
		})
		
		_self.onRejectedCallback.push((val) => {
			let x = onRejected(val); 
			// 判断x的类型
			if(x instanceof _promise) {
				x.then(resolve, reject);
			} else {
				reject(x);
			}
		})
	})
}

看了一些大佬的文章,一步一步解读最后写了这篇Promise基本原理的实现,有理解不对的地方希望大家指正!

你可能感兴趣的:(Promise实现思路)