# 一、其他 Promise 方法
除了上面介绍的常见的 Promise 原型对象上的方法,和 Promise 函数对象部分方法外。还有其他的方法需要我们了解一下。
在实际开发中,Promise 常用在处理异步请求中。如果只是一个请求还好,如果同时在 Promise 中处理多个异步请求呢?
# 1、Promise.all
Promise.all()可以将多个 Promise 实例包装成一个新的 Promise 实例
const p = Promise.all([p1, p2, p3])
// p1 && p2 && p3
p1、p2、p3 都为 fulfilled 状态时,p 的状态才会变为 fulfilled。
只要 p1、p2、p3 其中的任何一个变为 rejected 状态时,p 的状态就会变为 rejected。
应用:处理多个类似的异步请求
- 常规方式
var list = [1, 3, 5]
list.forEach((item) => {
$.ajax(`https://jsonplaceholder.typicode.com/posts/${item}`).then((res) => {
console.log(res) // 分为三次打印 {…}
})
})
- Promise.all 方式
var list = [1, 3, 5]
function getData(list) {
var newlist = list.map((item) => $.ajax(`https://jsonplaceholder.typicode.com/posts/${item}`))
return Promise.all(newlist) // 🎈
}
getData(list)
.then((res) => {
console.log(res) // [{…}, {…}, {…}]
})
.catch((err) => {
console.log(err)
})
# 2、Promise.race
Promise.race()可以将多个 Promise 实例包装成一个新的 Promise 实例
const p = Promise.race([p1, p2, p3])
// p1 || p2 || p3
与前面的 Promise.all 不同的是,只要 p1、p2、p3 其中的任何一个状态发生变化,p 的状态就会跟着变化
应用 1:差异比较
var p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('data1')
}, 1000)
})
var p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('data2')
}, 2000)
})
Promise.race([p1, p2]).then((res) => {
console.log(res) // data1
})
应用 2:请求超时检测
var p1 = $.ajax('https://jsonplaceholder.typicode.com/comments?postId=1')
var p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('请求超时')
}, 4000)
})
Promise.race([p1, p2])
.then((res) => {
console.log(res) // {…}
})
.catch((err) => {
console.log(err)
})
应用 3:多节点服务器请求
var p1 = ajax('https://jsonplaceholder.typicode.com/posts/1')
var p2 = ajax('https://jsonplaceholder.typicode.com/posts/2')
var p3 = ajax('https://jsonplaceholder.typicode.com/posts/3')
var p4 = ajax('https://jsonplaceholder.typicode.com/posts/4')
Promise.race([p1, p2, p3, p4])
.then((res) => {
console.log(res) // {…}
})
.catch((err) => {
console.log(err)
})
# 3、Promise.allSettled
在前面的 Promise.all 方法中,我们发现:
只要 p1、p2、p3 其中的任何一个变为 rejected 状态时,p 的状态就会变为 rejected。
但这会导致一个问题,成功的数据会因为某个接口发生错误而无法得到数据。
ES2020 即 ES11 发布的 Promise.allSettled 方法就可以解决上述问题。
const p = [ajax('/200接口'), ajax('/401接口')]
Promise.allSettled(promises)
.then((res) => {
{
// 成功的请求响应数据
const successList = res.filter((item) => item.status === 'fulfilled')
// 失败的请求响应数据
const errorList = res.filter((item) => item.status === 'rejected')
}
})
.catch((err) => {
console.log(err)
})
# 4、Promise.any
Promise.any()可以将多个 Promise 实例包装成一个新的 Promise 实例
const p = Promise.any([p1, p2, p3])
只要 p1、p2、p3 其中的任何一个变为 fulfilled 状态时,p 的状态就会变为 fulfilled。
p1、p2、p3 都为 rejected 状态时,p 的状态才会变为 rejected。
通过比较 Promise.all 的状态变化关系和 Promise.any 的转态变化关系恰恰相反
- 会员联盟系统
const p1 = new Promise((resolve, reject) => {
// 沃尔玛的登录逻辑
})
const p2 = new Promise((resolve, reject) => {
// 华润的登录逻辑
})
const p3 = new Promise((resolve, reject) => {
// 盒马的登录逻辑
})
Promise.any([p1, p2, p3])
.then((res) => {
console.log(res)
// 跳转到主页
})
.catch((err) => {
console.log(err)
// 请注册
})
# 二、执行顺序问题 ✍
提示
- Promise 的 excutor 函数是 同步回调
- Promise 的.then / .catch 中的 成功|失败函数 是异步回调
# 1、问题 1
是先 promise 改变状态,还是先指定回调函数?
- 常规
new Promise((resolve, reject) => {
setTimeout(() => {
console.log('--- one ---')
// 后改变状态(异步执行回调函数)
resolve(1)
})
}).then(
// 先指定回调函数
(res) => {
console.log('--- two ---')
},
(err) => {}
)
console.log('--- -- ---')
- 也可以
new Promise((resolve, reject) => {
console.log('--- one ---')
// 先改变状态
resolve(1)
}).then(
// 后指定回调函数(异步执行回调函数)
(res) => {
console.log('--- two ---')
},
(err) => {}
)
console.log('--- -- ---')
# 2、问题 2
promise.then() 返回的新 promise 的结果状态由什么决定?
new Promise((resolve, reject) => {
resolve(1)
// reject(1)
})
.then(
(res) => {
console.log('onFulfillment-1', res)
// return undefined // 默认
// return 2
// return Promise.resolve(3)
// throw 4
},
(err) => {
console.log('onRejection-1', err)
}
)
.then(
(res) => {
console.log('onFulfillment-2', res)
},
(err) => {
console.log('onRejection-2', err)
}
)
结果:
onFulfillment-1 1
onFulfillment-1 undefined
// 或者
onRejection-1 1
onFulfillment-1 undefined
# 3、问题 3
Promise.then()的链式调用中,同步/异步任务执行顺序是怎样的?
new Promise((resolve, reject) => {
setTimeout(() => {
console.log('开始执行:异步任务 1')
resolve(1)
})
})
.then((res) => {
console.log('任务1的结果:', res)
console.log('开始执行:同步任务 2')
return 2
})
.then((res) => {
console.log('任务2的结果:', res)
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('开始执行:异步任务 3')
resolve(3)
})
})
})
.then((res) => {
console.log('任务3的结果:', res)
})
console.log('--- -- ---')
# 4、问题 4
什么是 Promise 异常传透?怎样中断 Promise 链?
new Promise((resolve, reject) => {
reject(1)
})
.then(
(res) => {}
// (err) => {throw reason} // 默认操作
)
.then(
(res) => {}
// (err) => {throw reason} // 默认操作
)
.catch((err) => {
console.log(err)
})
new Promise((resolve, reject) => {
reject(1)
})
.then(
(res) => {},
(err) => {
console.log('onRejection-1', err)
// 中断promise链
return new Promise(() => {})
}
)
.then(
(res) => {
console.log('onFulfillment-1', res)
},
(err) => {
console.log('onRejection-1', err)
}
)