# 一、其他 Promise 方法
除了上面介绍的常见的 Promise 原型对象上的方法,和 Promise 函数对象部分方法外。还有其他的方法需要我们了解一下。
在实际开发中,Promise 常用在处理异步请求中。如果只是一个请求还好,如果同时在 Promise 中处理多个异步请求呢?
# 1、Promise.all
Promise.all()可以将多个 Promise 实例包装成一个新的 Promise 实例
const p = Promise.all([p1, p2, p3]) // p1 && p2 && p3
Copied!
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) // 分为三次打印 {…} }) })
Copied!
- 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) })
Copied!
# 2、Promise.race
Promise.race()可以将多个 Promise 实例包装成一个新的 Promise 实例
const p = Promise.race([p1, p2, p3]) // p1 || p2 || p3
Copied!
与前面的 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 })
Copied!
应用 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) })
Copied!
应用 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) })
Copied!
# 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) })
Copied!
# 4、Promise.any
Promise.any()可以将多个 Promise 实例包装成一个新的 Promise 实例
const p = Promise.any([p1, p2, p3])
Copied!
只要 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) // 请注册 })
Copied!
# 二、执行顺序问题 ✍
提示
- 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('--- -- ---')
Copied!
- 也可以
new Promise((resolve, reject) => { console.log('--- one ---') // 先改变状态 resolve(1) }).then( // 后指定回调函数(异步执行回调函数) (res) => { console.log('--- two ---') }, (err) => {} ) console.log('--- -- ---')
Copied!
# 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) } )
Copied!
结果:
onFulfillment-1 1 onFulfillment-1 undefined // 或者 onRejection-1 1 onFulfillment-1 undefined
Copied!
# 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('--- -- ---')
Copied!
# 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) })
Copied!
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) } )
Copied!