promise是前端解决异步的一个重要的东西。其主要使用如下:
const p1 = new Promise((resolve, reject) => {
// 此处走then方法
resolve(111)
// 此处走catch方法
// reject(222)
})
p1.then((res) => {
console.log(res);
}).catch(err => {
console.log(err);
})
1、先来实现一个基础版本
可以传入构造函数,有resolve,reject,可以调用then方法:
class MyPromise {
constructor(executor) {
//一共有三种状态,pending、fulfilled、reject
this.status = 'pending';
//成功的原因
this.value = undefined;
//失败的原因
this.reason = undefined;
let resolveFn = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled';
this.value = value;
}
}
let rejectFn = (reason) => {
if (this.status === 'pending') {
this.status = 'reject';
this.reason = reason;
}
}
try {
executor(resolveFn, rejectFn);
} catch (e) {
rejectFn(e)
}
}
then (onFulFilled, onReject) {
if (this.status === 'fulfilled') {
onFulFilled(this.value)
}
if (this.status === 'reject') {
onReject(this.reason)
}
}
}
const my1 = new MyPromise((resolve) => {
console.log(1);
resolve('resolve2')
})
my1.then(res => {
console.log(res);
})
2、升级版本,遇到异步
在如果resolve没有立即执行,遇到了异步,应该如何解决,主要的思路就是:维护一个队列,加上一个数组去缓存执行函数:
我们分别维护了一个数组,当然我们在promise仍旧是pending状态的时候调用then方法,就会把这两个状态的回调函数缓存起来。等到我们调用resolve或者reject确认了promise的状态时,就会去调用对应的缓存队列执行回调。
class MyPromise {
constructor(executor) {
executor(this.resolve.bind(this), this.reject.bind(this))
}
state = 'pending'
// 成功的值
value = null
// 失败的值
reason = null
// 当走到then/catch方法的时候,如果状态没变化,就暂时先声明一个变量去缓存方法,等到状态变化的时候再去执行
onFulfilledCallbackList = []
onRejectedCallbackList = []
resolve(value) {
if (this.state !== 'pending') return;
this.state = 'fulfilled'
this.value = value;
// 状态变化的时候再去执行相应的函数,从队列里面出来
this.onFulfilledCallbackList.forEach(callback => callback(value))
this.onFulfilledCallbackList = []
}
reject(reason) {
if (this.state !== 'pending') return;
this.state = 'rejected'
this.reason = reason
this.onRejectedCallbackList.forEach(callback => callback(reason))
this.onRejectedCallbackList = []
}
then(onFulFilled, onRejected) {
return new MyPromise((res, rej) => {
if (this.state === 'fulfilled') {
res(onFulFilled(this.value))
};
if (this.state === 'rejected') {
rej(onRejected(this.reason))
};
// 假如遇到了异步,那state依然是pengding状态,先放入队列里面
if (this.state === 'pending') {
this.onFulfilledCallbackList.push(onFulFilled)
this.onRejectedCallbackList.push(onRejected)
};
})
}
}
const myP1 = new MyPromise((resolve, reject) => {
console.log('立即执行');
resolve(111)
// setTimeout(() => {
// resolve(111)
// }, 3000)
}).then(res => {
console.log('成功了', res);
}, err => {
console.log('失败了', err);
}).then(res => {
console.log('链式调用then方法', res);
})
3、实现then的链式调用
实现的思路就是在then方法中返回一个自己开发的promise就可以了关键代码如下:
class MyPromise {
constructor(executor) {
//一共有三种状态,pending、fulfilled、reject
this.status = 'pending';
//成功的原因
this.value = undefined;
//失败的原因
this.reason = undefined;
let resolveFn = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled';
this.value = value;
}
}
let rejectFn = (reason) => {
if (this.status === 'pending') {
this.status = 'reject';
this.reason = reason;
}
}
try {
executor(resolveFn, rejectFn);
} catch (e) {
rejectFn(e)
}
}
then (onFulFilled, onReject) {
// 此次返回一个MyPromise就可以实现then的链式调用了,这里是关键代码
return new MyPromise((resolve, reject) => {
if (this.status === 'fulfilled') {
// 将上一个promise的返回值传入到下一个构造函数的resolve方法中,如此就实现了then的链式调用
resolve(onFulFilled(this.value))
}
if (this.status === 'reject') {
reject(onReject(this.reason))
}
})
}
}
const my1 = new MyPromise((resolve) => {
console.log(1);
resolve('resolve2')
})
my1.then(res => {
console.log(res);
return '25'
}).then(res => {
console.log(res);
return '35'
}).then(res => {
console.log(res);
return '45'
}).then(res => {
console.log(res);
})
// 打印结果为:1,resolve2,25,35,45
4、实现Promise.resolve、Promise.reject和Promise.catch
这里主要就是讲解catch、resolve、reject方法是如何实现的;
class MyPromise {
constructor(executor) {
executor(this.resolve.bind(this), this.reject.bind(this))
}
state = 'pending'
// 成功的值
value = null
// 失败的值
reason = null
// 当走到then/catch方法的时候,如果状态没变化,就暂时先声明一个变量去缓存方法,等到状态变化的时候再去执行
onFulfilledCallbackList = []
onRejectedCallbackList = []
resolve(value) {
if (this.state !== 'pending') return;
this.state = 'fulfilled'
this.value = value;
// 状态变化的时候再去执行相应的函数,从队列里面出来
this.onFulfilledCallbackList.forEach(callback => callback(value))
this.onFulfilledCallbackList = []
}
reject(reason) {
if (this.state !== 'pending') return;
this.state = 'rejected'
this.reason = reason
this.onRejectedCallbackList.forEach(callback => callback(reason))
this.onRejectedCallbackList = []
}
then(onFulFilled, onRejected) {
return new MyPromise((res, rej) => {
if (this.state === 'fulfilled') {
res(onFulFilled(this.value))
};
if (this.state === 'rejected') {
rej(onRejected(this.reason))
};
// 假如遇到了异步,那state依然是pengding状态,先放入队列里面
if (this.state === 'pending') {
this.onFulfilledCallbackList.push(onFulFilled)
this.onRejectedCallbackList.push(onRejected)
};
})
}
catch(errCb) {
return this.then(null, errCb);
}
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value);
});
}
static reject(value) {
return new MyPromise((resolve, reject) => {
reject(value);
});
}
}
const myP1 = new MyPromise((resolve, reject) => {
console.log('立即执行');
reject(111)
// setTimeout(() => {
// reject(111)
// }, 3000)
})
myP1.then(res => {
console.log('不走这里', res);
}, (err) => {
console.log('onReject捕获了失败', err);
}).catch(res => {
console.log('myP1** catch 方法', res);
})
MyPromise.reject('试一下MyPromise**reject').catch(res => {
console.log(res);
})
MyPromise.resolve('试一下MyPromise**resolve').then(res => {
console.log(res);
})
5、Promise.其他方法
5.1、Promise.all
all方法会接受一个都是Promise的数组,然后内部回去处理这个数组。
首先,我们声明了两个变量,一个存储结果的数组,这个结果是指resolve成功后的onFulfilled回调的value,一个是计数器。
然后,我们去循环整个传入的promises,让每一个promise传递给Promise.resolve去执行,然后,我们用一个processResult去处理返回的data和当前的下标i,
然后我们还要处理一下reject,那么这里要注意哈,对于all方法来说,只要有一个出错了,那么整个all执行的结果就是rejected的,所以reject不用特殊处理,直接reject就好了,不需要添加进数组这个那个的。
那么继续,processResult每当我们执行一次的时候,会根据传入的下标的位置去存储结果,这样处理其实就是为了按照传入promise的先后顺序去存储结果,然后先++times再去和promises的length长度去做比较,换句话说就是计数嘛,如果相等,就直接resolve最终的result即可。
以上就是全部的思路了,来看一下细节的代码:
static all(promises) {
let result = [];
let times = 0;
return new Promise((resolve, reject) => {
function processResult(data, index) {
result[index] = data;
if (++times === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
const promise = promises[i];
Promise.resolve(promise).then((data) => {
processResult(data, i);
}, reject);
}
});
}
来看一下all的调用代码:
const myP1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 300)
})
const myP2 = new MyPromise((resolve, reject) => {
resolve(222)
})
const myP3 = new MyPromise((resolve, reject) => {
resolve(333)
})
const p = MyPromise.all([myP1, myP2, myP3]).then(res => {
console.log('all', res);// 打印结果为:[111, 222, 333]
})
5.2、Promise.race
先来看个例子:
const p = MyPromise.race([myP1, myP2, myP3])
race方法接收一个数组,数组中只要 myP1、myP2、myP3之中有一个实例率先改变状态,p的状态就跟着变。那个率先改变的promise实例的返回值,就传递给p的回调函数。
换句话说就是,只要有一个结果就行了,不管这个结果是啥。谁跑的快我就算谁是第一,这就是race的意思。所以需要循环一下全部执行一遍,谁有结果了就完事儿了。
关键代码如下:
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
let promise = promises[i];
Promise.resolve(promise).then(resolve, reject);
}
});
}
来看一下调用:
const myP1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 300)
})
const myP2 = new MyPromise((resolve, reject) => {
resolve(222)
})
const myP3 = new MyPromise((resolve, reject) => {
resolve(333)
})
const p = MyPromise.race([myP1, myP2, myP3]).then(res => {
console.log('race', res);// 打印结果为 222
})
5.3、Promise.allSettled
这个方法的意思就是不管成功或者失败,会返回所有异步的结果。
其实跟all方法很类似,只要修改一下all方法就可以了,result存的内容也不太一样,多了个状态,会告诉你是失败的结果还是成功的结果。关键代码如下:
static allSettled(promises) {
let result = [];
let times = 0;
return new Promise((resolve, reject) => {
function processResult(data, index, status) {
// 这里调整成了对象的形式
result[index] = { status, value: data };
if (++times === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
const promise = promises[i];
// 不管成功与失败就都这样子来
Promise.resolve(promise).then(
(data) => {
processResult(data, i, "fulfilled");
},
(err) => {
processResult(err, i, "rejected");
}
);
}
});
}
来看一下调用allSettled方法吧:
const myP1= new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 300)
})
const myP2 = new MyPromise((resolve, reject) => {
reject(222)
})
const myP3 = new MyPromise((resolve, reject) => {
resolve(333)
})
const p = MyPromise.allSettled([myP1, myP2, myP3]).then(res => {
console.log('all', res);
/*
打印结果如下:
[
{
"status": "fulfilled",
"value": 111
},
{
"status": "rejected",
"value": 222
},
{
"status": "fulfilled",
"value": 333
}
]
*/
})
5.4、Promise.finally
这个方法表示的意思是,不管Promise对象最后的状态如何,都会执行这个方法,就是我不管你Promise最后是fulfilled还是rejected,都会执行finally的回调。关键代码如下:
finally(finallyCallback) {
let p = this.constructor;
return this.then(
(data) => {
return p.resolve(finallyCallback()).then(() => data);
},
(err) => {
return p.resolve(finallyCallback()).then(() => {
throw err;
});
}
);
}
调用的代码:
MyPromise.resolve('test-finally').then(res => {
console.log('then:', res);
}, err => {
console.log('catch:', err);
}).finally(() => {
console.log('finally');
})
/*
* 最终打印结果为:
* then: test-finally
* finally
* */
6、完整的代码
这个完整的代码包含:基础版本,升级版本,resolve、reject、then、catch、all、race、allSettled、finally,如下所示:
class MyPromise {
constructor(executor) {
executor(this.resolveFn.bind(this), this.rejectFn.bind(this))
}
state = 'pending'
// 成功的值
value = null
// 失败的值
reason = null
// 当走到then/catch方法的时候,如果状态没变化,就暂时先声明一个变量去缓存方法,等到状态变化的时候再去执行
onFulfilledCallbackList = []
onRejectedCallbackList = []
resolveFn(value) {
if (this.state !== 'pending') return;
this.state = 'fulfilled'
this.value = value;
// 状态变化的时候再去执行相应的函数,从队列里面出来
this.onFulfilledCallbackList.forEach(callback => callback(value))
this.onFulfilledCallbackList = []
}
rejectFn(reason) {
if (this.state !== 'pending') return;
this.state = 'rejected'
this.reason = reason
this.onRejectedCallbackList.forEach(callback => callback(reason))
this.onRejectedCallbackList = []
}
then(onFulFilled, onRejected) {
return new MyPromise((res, rej) => {
if (this.state === 'fulfilled') {
res(onFulFilled(this.value))
};
if (this.state === 'rejected') {
rej(onRejected(this.reason))
};
// 假如遇到了异步,那state依然是pengding状态,先放入队列里面
if (this.state === 'pending') {
this.onFulfilledCallbackList.push(onFulFilled)
this.onRejectedCallbackList.push(onRejected)
};
})
}
catch(errCb) {
return this.then(null, errCb);
}
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value);
});
}
static reject(value) {
return new MyPromise((resolve, reject) => {
reject(value);
});
}
static all(promises) {
let result = [];
let times = 0;
return new Promise((resolve, reject) => {
function processResult(data, index) {
result[index] = data;
if (++times === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
const promise = promises[i];
Promise.resolve(promise).then((data) => {
processResult(data, i);
}, reject);
}
});
}
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
let promise = promises[i];
Promise.resolve(promise).then(resolve, reject);
}
});
}
static allSettled(promises) {
let result = [];
let times = 0;
return new Promise((resolve, reject) => {
function processResult(data, index, status) {
// 这里调整成了对象的形式
result[index] = { status, value: data };
if (++times === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
const promise = promises[i];
// 不管成功与失败就都这样子来
Promise.resolve(promise).then(
(data) => {
processResult(data, i, "fulfilled");
},
(err) => {
processResult(err, i, "rejected");
}
);
}
});
}
finally(finallyCallback) {
let p = this.constructor;
return this.then(
(data) => {
return p.resolve(finallyCallback()).then(() => data);
},
(err) => {
return p.resolve(finallyCallback()).then(() => {
throw err;
});
}
);
}
}
最后:参考链接
这个链接里面讲的很详细了,有空看一下,把他们都内化成自己的知识。