我们知道,Promise的then是可以有多个,多次调用的,比如:
let promise = new MyPromise((resolve, reject) => {
resolve('成功...');
})
// 立即执行,resolve还未执行,所以status仍然是pendding
// 所以需要存储这些事态
promise.then((value) => {
console.log(1, value);
}, (err) => {
console.log(1, err);
});
// 由于支持链式调用,多个then回调,可能在状态还未变化之前,就已经执行了;
// 所以需要把回调数组缓存起来
promise.then((value) => {
console.log(2, value);
}, (err) => {
console.log(2, err);
});
promise.then((value) => {
console.log(3, value);
}, (err) => {
console.log(3, err);
});
此处运算的结果,
即:不仅可以多次调用then获取最终的运算结果,promise的状态也会保持一致;
5、那么这种情况,我们应该是在阶段一的基础,用一个数组来存储这些then的事件,在resolve、reject事件触发的时候,通过循环shift,把事件回调一个个执行完。
并且,Promise中的运算是支持异步的,那么如果:
let promise = new MyPromise((resolve, reject) => {
// resolve('成功');
setTimeout(() => {
resolve('成功...');
}, 2000);
// reject('失败');
})
在阶段一的基础下,他在then调用的时候,是直接发起回调的。如果运算中添加了异步,此时Promise的状态仍然是pendding,那么就没办法触发回调。
6、在then增加最后一个状态判断,pendding的判断,将事件缓存起来
const PENDDING = 'pendding'; // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor (executor) {
executor(this.resolve, this.reject);
}
// 默认等待
status = PENDDING;
// 成功之后的值
value = undefined;
// 失败原因
reason = undefined;
successCallBack = []
failCallBack = [];
// 定义箭头函数,由于使用是直接调用的,所以使用箭头函数,
// 让this指向promise对象
resolve = (value) => {
// 不是等待,拒绝执行
// 将状态更改为成功
if (this.status !== PENDDING) {
return;
}
this.status = FULFILLED;
// 保存成功之后的值
this.value = value;
// 判断成功回调是否存在
// if (this.successCallBack) {
// this.successCallBack(this.value);
// }
while (this.successCallBack.length) {
this.successCallBack.shift()(this.value);
}
}
reject = (reason) => {
// 不是等待,拒绝执行
if (this.status !== PENDDING) {
return;
}
// 将状态更改为失败
this.status = REJECTED;
// 保存失败原因
this.reason = reason;
// 判断失败回调是否存在
// if (this.failCallBack) {
// this.failCallBack(this.reason);
// }
while (this.failCallBack.length) {
this.failCallBack.shift()(this.reason);
}
}
then = (successCallBack, failCallBack) => {
// 判断状态
if (this.status === FULFILLED) {
successCallBack(this.value);
} else if (this.status === REJECTED) {
failCallBack(this.reason);
} else {
// 等待
// 由于异步,状态不一定在代码运行到then的时候,
// 状态发生变化,所以此时,pendding,需要把回调存起来
this.successCallBack.push(successCallBack);
this.failCallBack.push(failCallBack);
}
}
}
通过在resolve、reject添加清空缓存事件的逻辑
while (this.successCallBack.length) {
this.successCallBack.shift()(this.value);
}
在then添加存储回调事件的逻辑
this.successCallBack.push(successCallBack);
this.failCallBack.push(failCallBack);
来完成then的多次调用和异步调用,一举两得
那么,根据Promise的then的使用,发现他不仅可以多次调用,还支持链式调用: 链式调用不止是then的使用,而且是上一次then运算结果,传入下一次then;
promise.then((value) => {
console.log(1, value);
return 100;
}, (err) => {
console.log(1, err);
}).then((value) => {
console.log(1, value);
}, (err) => {
console.log(1, err);
});
7、想要链式调用,就得return,那么then之后仍然是使用Promise的方法,那么then的return就应该return一个新的Promise对象,
那么then的代码最终实现如下:
then = (successCallBack, failCallBack) => {
let promise2 = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) {
// 异步代码,为了获取promise2,用于判断then返回的res对象是否是自己本身,
// 需要拦截
setTimeout(() => {
// setTimeout 是为了让promise实例化先赋值给promise2,
// 这样子才可以被赋值的promise2,
// promise2 初始值undefined
let res = successCallBack(this.value);
// 提供给下一个then调用
// 判断res 是普通纸还是promise对象
// 如果是普通值,是可以直接进行回传
// 如果是promise,需要查看promise返回的结果
// 根据结果成功,失败调用resolve或者是reject
// resolve(res);
this.resolvePromise(promise2, res, resolve, reject);
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
let res = failCallBack(this.reason);
// reject(res);
this.rejectPromise(promise2, res, resolve, reject);
}, 0);
} else {
// 等待
// 由于异步,状态不一定在代码运行到then的时候,
// 状态发生变化,所以此时,pendding,需要把回调存起来
this.successCallBack.push(() => {
setTimeout(() => {
// setTimeout 是为了让promise实例化先赋值给promise2,
// 这样子才可以被赋值的promise2,
// promise2 初始值undefined
let res = successCallBack(this.value);
// 提供给下一个then调用
// 判断res 是普通纸还是promise对象
// 如果是普通值,是可以直接进行回传
// 如果是promise,需要查看promise返回的结果
// 根据结果成功,失败调用resolve或者是reject
// resolve(res);
this.resolvePromise(promise2, res, resolve, reject);
}, 0)
});
this.failCallBack.push(() => {
setTimeout(() => {
let res = failCallBack(this.reason);
// reject(res);
this.rejectPromise(promise2, res, resolve, reject);
}, 0);
});
}
});
// 下一个then获取到的就是此时的promise2,而在promise2内部根据状态,
// 回调resolve 或者reject来出发链式调用的then
return promise2;
}
resolvePromise (promise2, res, resolve, reject) {
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
}
rejectPromise (res, resolve, reject) {
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
reject(res);
}
}
这里增加了resolvePromise 、rejectPromise 方法,用来统一处理整个then重复的resolve、reject回调
8、由于返回的是一个新对象,如果没有添加setTimeout来异步处理,而是立即返回promise2,那么此时promise2是空的,因为还未赋值。只有在setTimeout回调之后,promise2才会被 new 赋值:
setTimeout(() => {
let res = successCallBack(this.value);
this.resolvePromise(promise2, res, resolve, reject);
}, 0)
9、then回调可以return 一个值,也支持return一个promise,所以需要判断是否 instanceof Promise,来手动执行触发then的resolve、reject状态,以便将上一个then的运算结果传给下一个then:
resolvePromise (promise2, res, resolve, reject) {
if (res instanceof MyPromise) {
// 是否promise对象,是则执行resolve,获取运算结果
res.then(resolve, reject);
} else {
resolve(res);
}
}
由于then可以回调,那么如果当then被误操作,回调了本身:
// 既然可以返回promise对象,那么如果返回自己本身呢?
var promise = new Promise((res, rej) => {res(100)});
var p1 = promise.then((value) => {console.log(value); return p1})
// Chaining cycle detected for promise #<Promise>
此时,Pormise是会抛出错误的,所以:
10、我们也需要添加一个判断传入的promise是否是回调本身,并且进行拦截
resolvePromise、rejectPromise需要添加多一行判断:
resolvePromise (promise2, res, resolve, reject) {
// res 是否属于promise
if (promise2 === res) {
// 自己返回自己, 直接报错
return reject(new TypeError('chaining cycle detected for promise #<Promise>'));
}
// ...
}
11、为了防止整个执行过程出现错误,我们需要添加一个捕获,将错误捕获之后默认调用reject回调
最终
阶段二:实现了then的多次调用、链式调用。结果传递、错误拦截等
const PENDDING = 'pendding'; // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor (executor) {
try {
// 捕获错误
executor(this.resolve, this.reject);
}catch(err) {
this.reject(err);
}
}
// 默认等待
status = PENDDING;
// 成功之后的值
value = undefined;
// 失败原因
reason = undefined;
successCallBack = []
failCallBack = [];
// 定义箭头函数,由于使用是直接调用的,所以使用箭头函数,让this指向promise对象
resolve = (value) => {
// 不是等待,拒绝执行
// 将状态更改为成功
if (this.status !== PENDDING) {
return;
}
this.status = FULFILLED;
// 保存成功之后的值
this.value = value;
// 判断成功回调是否存在
// if (this.successCallBack) {
// this.successCallBack(this.value);
// }
while (this.successCallBack.length) {
this.successCallBack.shift()();
}
}
reject = (reason) => {
// 不是等待,拒绝执行
if (this.status !== PENDDING) {
return;
}
// 将状态更改为失败
this.status = REJECTED;
// 保存失败原因
this.reason = reason;
// 判断失败回调是否存在
// if (this.failCallBack) {
// this.failCallBack(this.reason);
// }
while (this.failCallBack.length) {
this.failCallBack.shift()();
}
}
then = (successCallBack, failCallBack) => {
successCallBack = successCallBack ? successCallBack : value => value;
failCallBack = failCallBack ? failCallBack : value => value;
let promise2 = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) {
// 异步代码,为了获取promise2,用于判断then返回的res对象是否是自己本身,
// 需要拦截
setTimeout(() => {
// setTimeout 是为了让promise实例化先赋值给promise2,
// 这样子才可以被赋值的promise2,
// promise2 初始值undefined
try {
let res = successCallBack(this.value);
// 提供给下一个then调用
// 判断res 是普通纸还是promise对象
// 如果是普通值,是可以直接进行回传
// 如果是promise,需要查看promise返回的结果
// 根据结果成功,失败调用resolve或者是reject
// resolve(res);
this.resolvePromise(promise2, res, resolve, reject);
} catch (err) {
reject(err);
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let res = failCallBack(this.reason);
// reject(res);
this.resolvePromise(promise2, res, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
} else {
// 等待
// 由于异步,状态不一定在代码运行到then的时候,
// 状态发生变化,所以此时,pendding,需要把回调存起来
this.successCallBack.push(() => {
setTimeout(() => {
// setTimeout 是为了让promise实例化先赋值给promise2,
// 这样子才可以被赋值的promise2,
// promise2 初始值undefined
try {
let res = successCallBack(this.value);
// 提供给下一个then调用
// 判断res 是普通纸还是promise对象
// 如果是普通值,是可以直接进行回传
// 如果是promise,需要查看promise返回的结果
// 根据结果成功,失败调用resolve或者是reject
// resolve(res);
this.resolvePromise(promise2, res, resolve, reject);
} catch (err) {
reject(err);
}
}, 0)
});
this.failCallBack.push(() => {
setTimeout(() => {
try {
let res = failCallBack(this.reason);
// reject(res);
this.resolvePromise(promise2, res, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
});
}
});
// 下一个then获取到的就是此时的promise2,而在promise2内部根据状态,
// 回调resolve 或者reject来出发链式调用的then
return promise2;
}
resolvePromise (promise2, res, resolve, reject) {
// res 是否属于promise
if (promise2 === res) {
// 自己返回自己, 直接报错
return reject(new TypeError('chaining cycle detected for promise #<Promise>'));
}
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
}
rejectPromise (res, resolve, reject) {
// res 是否属于promise
if (promise2 === res) {
// 自己返回自己, 直接报错
return reject(new TypeError('chaining cycle detected for promise #<Promise>'));
}
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
reject(res);
}
}
}