我写这篇文章不打算介绍Promise产生的原因以及它解决的问题,我只是想写一篇关于实现自己Promise的文章。如果代码以及逻辑有什么不对的地方,请大家指出来。就这些,开始正题。
前提:我们要知道Promise是基于Promises/A+规范的。其中好多变量和方法名都是从这里来的。 我们先从Promise的使用开始,写几个测试例子。
let promise = new Promise((resolve, reject) =>{
// console.log("1");
// resolve("成功");
// reject("失败");
// console.log("2");// 第一步
// reject("失败");
// resolve("成功");// 第二步
// setTimeout(() => {
// resolve("success");
// }, 2000);
throw new Error("手动抛出错误");// 第四步
});
promise.then((value) => {
console.log("then第一个方法:"+value);
}, (err) => {
console.log("then第二个方法:"+err);
})
promise.then((value) => {
console.log("then第一个方法:"+value);
}, (err) => {
console.log("then第二个方法:"+err);
})
console.log("3");
复制代码
第一步输出
- 1
- 2
- 3
- then第一个方法:成功
- then第一个方法:成功
第二步输出
- 3
- then第二个方法:失败
- then第二个方法:失败
第三步输出
- 3 两秒之后
- then第一个方法:success
- then第一个方法:success
第四步输出
- 3
- then第二个方法:Error: 手动抛出错误
- then第二个方法:Error: 手动抛出错误
最后输出“成功”说明 then是异步执行的
根据以上几个例子我们可以推出以下几点内容:
- Promise是一个构造函数(使用了 new)
- Promise接收一个参数,并且这个参数是一个函数(为了方便描述,我们称之为 executor)
- executor在 new Promise时执行
- new Promise中可以支持异步行为(第三步)
- executor有两个参数(resolve,reject)
- resolve和reject不会我们传进去的,说明是属于Promise内容提供的
- resolve和reject都是函数,并且都接收一个参数。看规范:resolve接收参数称之为value,reject接收参数称之为reason
- 每个Promise实例上都有then方法
- then方法是异步的
- then方法中有两个参数onFulfilled和onRejected 分别是成功的回调(执行resolve)和失败的回调(执行reject)。看这里
- 一个Promise中resolve和reject只会执行一个,规范中有提到 Promise States,大家可以看下
- 同一个promise的实例可以then多次,成功时回调用所有的成功方法,失败时回调用所有的失败方法
- 如果发现错误就会走入失败态
这么一大坨东西,看着有点乱。我们就根据我们得出的结论开始写属于自己的Promise。写的过程中思路慢慢就清晰了。
let myPromise = function (executor) {
let self = this;//缓存一下this
self.status = 'pending';// 状态管理 状态的变化只能由pending变为resolved或者rejected。一件事情不能既成功又失败。所以resolved和rejected不能相互转化。
self.value = undefined;// 成功后的值 传给resolve
self.reason = undefined;//失败原因 传给reject
self.onResolvedCallbacks = [];// 存放then中成功的回调
self.onRejectedCallbacks = []; // 存放then中失败的回调
// 这里说明一下,第三步使用定时器。执行完 new Promise 之后,会执行then方法,此时会把then中的方法缓存起来,并不执行:此时状态还是pending。等到定时器2秒之后,执行
// resolve|reject 时,而是依次执行存放在数组中的方法。 参考发布订阅模式
function resolve(value) {
// pending => resolved
if (self.status === 'pending') {
self.value = value;
self.status = 'resolved';
// 依次执行缓存的成功的回调
self.onResolvedCallbacks.forEach(fn => fn(self.value));
}
}
function reject(reason) {
// pending => rejected
if (self.status === 'pending') {
self.value = value;
self.status = 'rejected';
// 依次执行缓存的失败的回调
self.onRejectedCallbacks.forEach(fn => fn(self.reason));
}
}
try {
//new Promise 时 executor执行
executor(resolve, reject);
} catch (error) {
reject(error);// 当executor中执行有异常时,直接执行reject
}
}
// 每个Promise实例上都有then方法
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
// 执行了 resolve
if (self.status === 'resolved') {
// 执行成功的回调
onFulfilled(self.value);
}
// 执行了 reject
if (self.status === 'rejected') {
// 执行失败的回调
onRejected(self.reason);
}
// new Promise中可以支持异步行为 当既不执行resolve又不执行reject时 状态是默认的等待态pending
if (self.status === 'pending') {
// 缓存成功的回调
self.onResolvedCallbacks.push(onFulfilled);
// 缓存失败的回调
self.onRejectedCallbacks.push(onRejected);
}
};
复制代码
说明一下:这是最简版,因为Promise的强大之处是链式调用。我们这个只是雏形,由于时间关系。我们先到这里。下一次我们基于这个雏形实现符合Promises/A+规范的完整版。
第一次发表文章,希望各位大虾多多支持。