promise
说起 promise ,很多小伙伴的第一反应就是异步操作,解决回调地狱,任务队列和事件循环,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败) ,一旦状态改变,就不会再变.....
这些点平常大家看面试题都已经快背下来了,这次我们搞点 promise 的实践玩法
开发的时候,我们经常使用到 promise ,是这样用的
function prom() {
return new Promise((resolve, reject) => {
// resolve(222);
reject(333)
});
}
function fn() {
prom().then(res => {
console.log('res', res); // 222
}).catch(err => {
console.log('err', err); //333
})
}
fn()
这样就可以在 .then 或者是.catch里面去做一些事情
但是有时候,事情往往不是那么简单的,假如遇到需要等待一段时间后再去执行后面的代码,这个时候单单使用 setTimeout 定时器已经不好使了,因为定时器是异步的,我们需要把异步转化为同步去执行,这个时候就可以使用 promise ,但是仅仅一个 promise 也不好搞,这个时候就可以配合 await 搞一个休眠函数来实现
function sleep(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222);
}, time);
});
}
async function fn() {
console.log('111', 111);
let res = await sleep(100);
console.log('res', res);
console.log('有了res之后我才执行的');
}
fn()
如你所见,没错,就是不用 .then 就获取到了 resolve 的返回值,只需要一个 await
async 和 await 可以直接返回 promise 的结果!!!!! 不用 .then() 去获取
但是 await 只能拿到 resolve 状态,因此对于错误是无能无力的
这个时候,就该 try...catch... 上场了,它可以捕获其代码块内部的任何错误,因此可以 catch 到 promise 的 reject 状态。
function sleep(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(222);
}, time);
});
}
async function fn() {
console.log('111', 111);
let res = null
try {
res = await sleep(100);
} catch (err) {
res = err
}
console.log('res', res);
console.log('有了res之后我才执行的');
}
fn()
再来看看平常用的少但是很好用的 api
-
finally:不管Promise对象最后状态是成功还是失败,都会执行new Promise((resolve, reject) => { setTimeout(() => { resolve(111) // reject(222) }); }).then(res => { console.log('res', res); }).catch(err => { console.log('err', err); }).finally(() => { console.log('我执行了'); })注意:
finally方法的回调函数不接受任何参数,这就意味着不知道Promise状态到底是fulfilled还是rejected -
all:可以将多个Promise实例,包装成一个新的Promise实例,参数是一个可迭代对象(一般都是一个数组),返回值是只返回一个Promise实例var p1 = Promise.resolve(1); var p2 = 2; var p3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 3); }); Promise.all([p1, p2, p3]).then(res => { console.log(res); // [1, 2, 3] // 返回值是一个数组 });注意: 只有在传入的数组中的值全部为成功才会返回成功,里面只要有任意一个失败了, 那
Promise.all将立即变为失败,而且返回值的顺序和传入参数的顺序是一致的!!它不管参数消耗的时间长那个短,一视同仁,它只看顺序!!但是整体返回值消耗的时间是有那个最长的时间决定的。这就带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all就是最好的选择!// 成功 var p1 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 1); }); var p2 = new Promise((resolve, reject) => { setTimeout(resolve, 300, 2); }); var p3 = new Promise((resolve, reject) => { setTimeout(resolve, 600, 3); }); var p4 = new Promise((resolve, reject) => { setTimeout(resolve, 200, 4); }); Promise.all([p1, p2, p3, p4]).then(res => { console.log(res); // [1, 2, 3, 4] // 返回值是一个数组 }).catch(err => { console.log('err', err); }) // 失败 var p1 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 1); }); var p2 = new Promise((resolve, reject) => { setTimeout(resolve, 200, 2); }); var p3 = new Promise((resolve, reject) => { setTimeout(resolve, 300, 3); }); var p4 = new Promise((resolve, reject) => { setTimeout(resolve, 400, 4); }); var p5 = new Promise((resolve, reject) => { reject('reject'); }); Promise.all([p1, p2, p3, p4, p5]).then(res => { console.log(res); }).catch(err => { console.log('err', err); // reject 返回值不是一个数组 }) -
allSettled:以promise组成的可迭代对象作为输入,并且返回一个Promise实例(数组)。 这个方法和all有点类似,但是不同点在于它要等到 所有这些参数实例都返回结果 ,不管是fulfilled还是rejected,才会返回一个promsie结果的对象数组。它的参数是一个promise组成的可迭代(例如Array)对象。const promise1 = Promise.resolve(11); const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 22)); const promises = [promise1, promise2]; Promise.allSettled(promises). then(results => results.forEach((result) => console.log(result.status)) ); // [ // { status: 'fulfilled', value: 11 }, // { status: 'rejected', value: 22 }, // ] -
any:它的参数和返回值和all差不多,区别在功能不一样,any只要有一个参数的状态改变了,就会立即返回,而且不会返回数组,而且any更注重成功,只要有一个执行通过,则认为成功,如果全部拒绝,则认为失败var p1 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 1); }); var p2 = new Promise((resolve, reject) => { resolve(2) }); var p3 = new Promise((resolve, reject) => { setTimeout(reject, 300, 3); }); var p4 = new Promise((resolve, reject) => { reject(4) }); Promise.any([p1, p2, p3, p4]).then(res => { console.log('res', res); // 2 }).catch(err => { console.log('err', err); }) Promise.any([p1, p2]).then(res => { console.log('res', res); // 2 }).catch(err => { console.log('err', err); }) // 注意了:这儿开始就体现出了它更注重成功 Promise.any([p1, p3]).then(res => { console.log('res', res); // 1 }).catch(err => { console.log('err', err); }) Promise.any([p1, p4]).then(res => { console.log('res', res); // 1 只要有成功,就会返回成功!! }).catch(err => { console.log('err', err); })注意: 如果全部都是
rejected,Promise.any()会抛出一个错误,它还不是一个一般的错误,而是一个AggregateErrorPromise.any([p3, p4]).then(res => { console.log('res', res); }).catch(err => { console.log('err', err); // err AggregateError: All promises were rejected }) -
race:这个方法同样是将多个Promise实例,包装成一个新的Promise实例,参数也是一个可迭代对象,返回值最先改变的那一个,顾名思义race就是赛跑,谁状态改变的快,跑得快,就先返回谁。而且不会返回数组var p1 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 1); }); var p2 = new Promise((resolve, reject) => { resolve(2) }); var p3 = new Promise((resolve, reject) => { setTimeout(reject, 300, 3); }); var p4 = new Promise((resolve, reject) => { reject(4) }); Promise.race([p1, p2, p3, p4]).then(res => { console.log('res', res); // 2 }).catch(err => { console.log('err', err); }) Promise.race([p1, p2]).then(res => { console.log('res', res); // 2 }).catch(err => { console.log('err', err); }) Promise.race([p1, p4]).then(res => { console.log('res', res); // 4 }).catch(err => { console.log('err', err); }) Promise.race([p2, p3]).then(res => { console.log('res', res); // 2 }).catch(err => { console.log('err', err); })
这一套 api 组合拳下来,基本满足了绝大部分的开发需求,什么一次请求多个接口,然后要这样操作那样操作这种情况再也不怕了,批量上传图片要做各种操作也不怕了