文章目录
深度剖析Promise实现
1.1 resolve和reject
运行结果:
这里说明了Promise的四个特点:
- 执行了resolve,Promise状态会变成fulfilled;
- 执行了reject,Promise状态会变成rejected;
- Promise状态不可逆,第一次成功就永久为fulfilled,第一次失败就永远状态为rejected;
- Promise中有throw的话,就相当于执行了reject
1.1.1 实现resolve和reject
- Promise的初始状态是pending;
- 需要对resolve和reject绑定this:确保resolve和reject的this指向永远指向当前的MyPromise实例,防止随着函数执行环境的改变而改变
class MyPromise {
constructor(executor) {
this.initData() // 初始化
this.initBind() // 初始化this指向
executor(this.resolve, this.reject)
}
initData() {
this.PromiseStatus = 'pending'
this.PromiseResult = null
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
this.PromiseStatus = 'fulfilled'
this.PromiseResult = value
}
reject(reason) {
this.PromiseStatus = 'rejected'
this.PromiseResult = reason
}
}
测试如下:
1.1.2 状态不可变
const test1 = new MyPromise((resolve, reject) => {
resolve('success')
reject('fail')
})
console.log(test1) // MyPromise { PromiseState: 'rejected', PromiseResult: 'fail' }
正确的应该是状态为fulfilled,但这里状态又变成了rejected。
Promise有三种状态:
- pending:等待中,是初始状态;
- fulfilled:成功状态;
- rejected:失败状态;
一旦状态从pending变为fulfilled或者rejected,那么此Promise实例的状态就不可以改变了。
这一步只需要:
resolve(value) {
// status是不可变的
if (this.PromiseStatus !== 'pending') return
this.PromiseStatus = 'fulfilled'
this.PromiseResult = value
}
reject(reason) {
// status是不可变的
if (this.PromiseStatus!== 'pending') return
this.PromiseStatus = 'rejected'
this.PromiseResult = reason
}
测试如下:
1.1.3 throw
Promise中有throw的话,就相当于执行了reject。这就要使用try catch了
+ try {
// 执行传进来的函数
executor(this.resolve, this.reject)
+ } catch (error) {
// 捕捉到错误直接执行reject
+ this.reject(error)
+ }
完整代码如下:
测试如下:
1.2 then
平时业务中then的使用一般如下:
// 马上输出 ”success“
const p1 = new Promise((resolve, reject) => {
resolve('success')
}).then(res => console.log(res), err => console.log(err))
// 1秒后输出 ”fail“
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('fail')
}, 1000)
}).then(res => console.log(res), err => console.log(err))
// 链式调用 输出 200
const p3 = new Promise((resolve, reject) => {
resolve(100)
}).then(res => 2 * res, err => console.log(err))
.then(res => console.log(res), err => console.log(err))
根据上述代码可以确定:
- then接收两个回调,一个是成功回调,一个是失败回调;
- 当Promise状态为fulfilled执行成功回调,为rejected执行失败回调;
- 如resolve或reject在定时器里,则定时器结束后再执行then;
- then支持链式调用,下一次then执行受上一次then返回值的影响;
1.2.1 实现then
then(onFulfilled, onRejected) {
//参数校验,确保一定是函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
if(this.PromiseStatus === 'fulfilled') {
onFulfilled(this.PromiseResult)
}
else if(this.PromiseStatus === 'rejected') {
onRejected(this.PromiseResult)
}
}
完整代码如下:
测试如下:
1.2.2 定时器
如何保证下述代码能够在1s后执行then的回调?
// 1秒后输出 ”fail“
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('fail')
}, 1000)
}).then(res => console.log(res), err => console.log(err))
我们不能确保1秒后才执行then函数,但是我们可以保证1秒后再执行then里的回调
在这1秒时间内,我们可以先把then里的两个回调保存起来,然后等到1秒过后,执行了resolve或者reject,咱们再去判断状态,并且判断要去执行刚刚保存的两个回调中的哪一个回调。
那么问题来了,我们怎么知道当前1秒还没走完甚至还没开始走呢?其实很好判断,只要状态是pending,那就证明定时器还没跑完,因为如果定时器跑完的话,那状态肯定就不是pending,而是fulfilled或者rejected
那是用什么来保存这些回调呢?建议使用数组,因为一个promise实例可能会多次then,用数组就一个一个保存了
代码改造
const test2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success') // 2秒后输出 success
}, 2000)
}).then(res => console.log(res), err => console.log(err))
1.2.3 链式调用
then支持链式调用,下一次then执行受上一次then返回值的影响
// 链式调用 输出 200
const p3 = new Promise((resolve, reject) => {
resolve(100)
}).then(res => 2 * res, err => console.log(err))
.then(res => console.log(res), err => console.log(err))
// 链式调用 输出300
const p4 = new Promise((resolve, reject) => {
resolve(100)
}).then(res => new Promise((resolve, reject) => resolve(3 * res)), err => console.log(err))
.then(res => console.log(res), err => console.log(err))
根据上文,可以得到:
- then方法本身会返回一个新的Promise对象;
- 如果返回值是promise对象,返回值为成功,新promise就是成功;
- 如果返回值是promise对象,返回值为失败,新promise就是失败;
- 如果返回值非promise对象,新promise对象就是成功,值为此返回值;
then是Promise上的方法,那如何实现then完还能再then呢?
then执行后返回一个Promise对象就行了,就能保证then完还能继续执行then;
代码如下:
class MyPromise {
constructor(executor) {
this.initData() // 初始化
this.initBind() // 初始化this指向
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
initData() {
this.PromiseStatus = 'pending'
this.PromiseResult = null
this.onFulfilledCallback = []
this.onRejectedCallback = []
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
if (this.PromiseStatus !== 'pending') return
this.PromiseStatus = 'fulfilled'
this.PromiseResult = value
while(this.onFulfilledCallback.length) {
this.onFulfilledCallback.shift()(this.PromiseResult)
}
}
reject(reason) {
if (this.PromiseStatus !== 'pending') return
this.PromiseStatus = 'rejected'
this.PromiseResult = reason
while(this.onRejectedCallback) {
this.onRejectedCallback.shift()(this.PromiseResult)
}
}
then(onFulfilled, onRejected) {
// 参数校验
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
var resultPromise = new MyPromise((resolve,reject)=> {
const resolvePromise = cb => {
try {
const x = cb(this.PromiseResult)
if(x === resultPromise && x) {
// 不能返回自身
throw new Error('不能返回自身。。。')
}
if(x instanceof MyPromise) {
// 谁知道返回的promise是失败成功?只有then知道
x.then(resolve,reject)
}
else {
// 非Promise就直接是成功
resolve(x)
}
} catch (error) {
reject(error)
throw new Error(error)
}
}
if(this.PromiseStatus === 'fulfilled') {
resolvePromise(onFulfilled)
}
else if(this.PromiseStatus === 'rejected') {
resolvePromise(onRejected)
}
else if(this.PromiseStatus === 'pending') {
// 保存回调
this.onFulfilledCallback.push(resolvePromise.bind(this, onFulfilled))
this.onRejectedCallback.push(resolvePromise.bind(this, onRejected))
}
})
// 返回包装后的Promise
return resultPromise
}
}
测试如下:
1.2.4 执行顺序
这里需要了解,then方法是微任务
const p = new Promise((resolve, reject) => {
resolve(1)
}).then(res => console.log(res), err => console.log(err))
console.log(2)
输出顺序是 2 1
这里为了实现类似的功能,使用setTimeout代替(setTimeout为宏任务,此处主要跟在全局上的console对比)
完整代码
class MyPromise {
constructor(executor) {
this.initData(); // 初始化
this.initBind(); // 初始化this指向
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
initData() {
this.PromiseStatus = "pending";
this.PromiseResult = null;
this.onFulfilledCallback = [];
this.onRejectedCallback = [];
}
initBind() {
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
}
resolve(value) {
if (this.PromiseStatus !== "pending") return;
this.PromiseStatus = "fulfilled";
this.PromiseResult = value;
while (this.onFulfilledCallback.length) {
this.onFulfilledCallback.shift()(this.PromiseResult);
}
}
reject(reason) {
if (this.PromiseStatus !== "pending") return;
this.PromiseStatus = "rejected";
this.PromiseResult = reason;
while (this.onRejectedCallback) {
this.onRejectedCallback.shift()(this.PromiseResult);
}
}
then(onFulfilled, onRejected) {
// 参数校验
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (val) => val;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
var resultPromise = new MyPromise((resolve, reject) => {
const resolvePromise = (cb) => {
setTimeout(() => {
try {
const x = cb(this.PromiseResult);
if (x === resultPromise && x) {
// 不能返回自身
throw new Error("不能返回自身。。。");
}
if (x instanceof MyPromise) {
// 谁知道返回的promise是失败成功?只有then知道
x.then(resolve, reject);
} else {
// 非Promise就直接是成功
resolve(x);
}
} catch (error) {
reject(error);
throw new Error(error);
}
});
};
if (this.PromiseStatus === "fulfilled") {
resolvePromise(onFulfilled);
} else if (this.PromiseStatus === "rejected") {
resolvePromise(onRejected);
} else if (this.PromiseStatus === "pending") {
// 保存回调
this.onFulfilledCallback.push(resolvePromise.bind(this, onFulfilled));
this.onRejectedCallback.push(resolvePromise.bind(this, onRejected));
}
});
// 返回包装后的Promise
return resultPromise;
}
}
const test4 = new MyPromise((resolve, reject) => {
resolve(1);
}).then(
(res) => console.log(res),
(err) => console.log(err)
);
console.log(2);
测试如下:
Promise方法
1.3.1 all
- 接收一个Promise数组,数组中如有非Promise项,则此项当做成功;
- 如果所有Promise都成功,则返回成功结果数组;
- 如果有一个Promise失败,则返回这个失败结果;
1.3.2 race
- 接收一个Promise数组,数组中如有非Promise项,则此项当做成功;
- 哪个Promise最快得到结果,就返回那个结果,无论成功失败;
1.3.3 allSettled
- 接收一个Promise数组,数组中如有非Promise项,则此项当做成功;
- 把每一个Promise的结果,集合成数组后返回;
1.3.4 any
- 接收一个Promise数组,数组中如有非Promise项,则此项当做成功;
- 如果有一个Promise成功,则返回这个成功结果;
- 如果所有Promise都失败,则报错;
小结
本章节只是实现了简版的Promise,完整的Promise还涉及到Promise/A+的规范,感兴趣的小伙伴可以到官网上学习
官方地址