找回密码
 立即注册
首页 资源区 代码 Web前端入门第 69 问:JavaScript Promise 提供的方法都 ...

Web前端入门第 69 问:JavaScript Promise 提供的方法都使用过吗?

寇油 2025-6-24 07:33:00
Promise 这个 API 曾在 JS 领域掀起过血雨腥风,以前的大佬们都喜欢手搓一个自己的 Promise 用以理解 Promise 的原理。
Promise 的诞生,应该多少都有受到 jQuery 的异步方法 $.Deferred() 影响。
应用场景

Promise 唯一作用就是在处理异步耗时任务的时候,不要出现回调地狱。在没有 Promise 之前,一般使用 callback 来解决异步问题,一般代码都是这样:
  1. a(() => {
  2.   b(()  => {
  3.     c(() => {
  4.       d(() => {})
  5.     })
  6.   })
  7. })
复制代码
就这样一层一层套进去,像套娃一样的回调方法,这就是所谓的 回调地狱。
使用 Promise 之后,代码就可以改成链式调用,避免了回调地狱:
  1. a()
  2. .then(() => {
  3.   return b()
  4. }).then(() => {
  5.   return c()
  6. }).then(() => {
  7.   return d()
  8. })
复制代码
常见用法

在代码中经常会看到这样使用 Promise:
  1. function task() {
  2.   return new Promise((resolve, reject) => {
  3.     setTimeout(() => {
  4.       resolve('耗时任务执行成功')
  5.     }, 1000)
  6.   })
  7. }
  8. // 开始执行耗时任务
  9. task().then(res => {
  10.   console.log('任务执行成功')
  11. }).catch(err => {
  12.   console.log('任务执行失败')
  13. }).finally(() => {
  14.   console.log('任务执行完成')
  15. })
  16. // 或者是这样
  17. task().then(res => {
  18.   console.log('任务执行成功')
  19. }, err => {
  20.   console.log('任务执行失败')
  21. }).finally(() => {
  22.   console.log('任务执行完成')
  23. })
复制代码
.then 方法接收两个参数,第一个参数是执行成功(fulfilled)的回调方法,第二个参数是执行失败(rejected)的回调方法。
.catch 方法用于捕获 Promise 中的错误,如果 Promise 执行失败,就会执行 .catch 方法,比如:
  1. function task() {
  2.   return new Promise((resolve, reject) => {
  3.     setTimeout(() => {
  4.       reject(new Error('任务执行失败'))
  5.     }, 1000)
  6.   })
  7. }
  8. task().catch(err => {
  9.   console.log(err.message)
  10. })
复制代码
.finally 方法无论 Promise 执行成功与否,都会执行的方法,一般多用于关闭 loading 这种效果,也可以用于清理资源。
Promise 的静态方法

以上三个方法都是 Promise 的实例方法,除了常用的实例方法外,Promise 还提供了一些静态方法,这些静态方法不是很常用(也可能是咱的段位太低),但在某些特定的需求场景中也是很有用的利器。
Promise.reject() 与 Promise.resolve()

这一对静态方法一般多用于将同步方法改成 Promise,比如:
  1. function task() {
  2.   if (Math.random() > 0.5) {
  3.     return Promise.reject(new Error('任务执行失败'))
  4.   }
  5.   return Promise.resolve('任务执行成功')
  6. }
  7. task().then((res) => console.log(res), err => console.error(err.message))
复制代码
其参数还支持返回一个 Promise 对象或者一个 thenable 对象。比如这样:
  1. function task1() {
  2.   return new Promise((resolve, reject) => {
  3.     if (Math.random() > 0.5) {
  4.       return resolve('耗时任务执行成功')
  5.     }
  6.     return reject(new Error('任务执行失败'))
  7.   })
  8. }
  9. function task2() {
  10.   // Promise 对象
  11.   return Promise.resolve(task1())
  12. }
  13. task2().then((res) => console.log(res), err => console.error(err.message))
  14. // ----------------------
  15. function task3() {
  16.   // thenable 对象
  17.   const thenable = {
  18.     then(onFulfill, onReject) {
  19.       if (Math.random() > 0.5) {
  20.         return onReject(new Error('任务执行失败'))
  21.       }
  22.       return onFulfill('任务执行成功')
  23.     },
  24.   }
  25.   return Promise.resolve(thenable)
  26. }
  27. task3().then((res) => console.log(res), err => console.error(err.message))
复制代码
Promise.all()

用于同时处理多个 Promise,如果全部都成功解决时,返回的 Promise 才会解决,但凡有一个被拒绝,则返回的 Promise 失败。
  1. const p1 = Promise.resolve('1')
  2. const p2 = Promise.reject('2')
  3. const p3 = Promise.resolve('3')
  4. Promise.all([p1, p3]).then(res => {
  5.   console.log('成功', res) // ['1', '3']
  6. }).catch(err => {
  7.   console.error('失败', err)
  8. })
  9. Promise.all([p2, p3]).then(res => {
  10.   console.log('成功', res)
  11. }).catch(err => {
  12.   console.error('失败', err) // 获得失败的返回值 2
  13. })
复制代码
Promise.allSettled()

与 Promise.all 有点不同,这个静态方法会等到所有的 Promise 都解决或者失败,然后返回一个 Promise,这个 Promise 的结果是一个数组,数组的元素是所有 Promise 的状态及响应结果。一般多用于多个接口同时请求场景,可以容忍部分接口异常的情况。
  1. const p1 = Promise.resolve('1')
  2. const p2 = Promise.reject('用于测试失败')
  3. const p3 = Promise.resolve('3')
  4. Promise.allSettled([p1, p2, p3]).then(res => {
  5.   res.forEach(result => {
  6.     if (result.status === 'fulfilled') {
  7.       console.log('成功:', result.value);
  8.     } else {
  9.       console.error('失败:', result.reason);
  10.     }
  11.   });
  12. })
复制代码
Promise.any()

也是用于处理多个 Promise,此方法的逻辑是:只获取第一个成功的 Promise 返回结果,如果全部失败,则返回一个失败的 Promise。
  1. const p1 = new Promise((resolve, reject) => setTimeout(reject, 100, '第一个失败'));
  2. const p2 = new Promise((resolve) => setTimeout(resolve, 200, '第二个成功'));
  3. const p3 = new Promise((resolve, reject) => setTimeout(reject, 300, '第三个失败'));
  4. const p4 = new Promise((resolve) => setTimeout(resolve, 200, '第四个成功'));
  5. Promise.any([p1, p2, p3, p4]).then(res => console.log('成功:', res)); // 成功: 第二个成功
  6. Promise.any([p1, p3]).catch(error => {
  7.   console.error('所有 Promise 失败:', error) // AggregateError: All promises were rejected
  8.   console.error('失败原因:', error.errors) // ['第一个失败', '第三个失败']
  9. });
复制代码
Promise.race()

此方法存在竞速的逻辑,谁最快返回就获得谁的结果,不论此结果是成功还是失败。
  1. const p1 = new Promise((resolve, reject) => setTimeout(reject, 100, '第一个失败'));
  2. const p2 = new Promise((resolve) => setTimeout(resolve, 100, '第二个成功'));
  3. Promise.race([p1, p2])
  4.   .then(res => console.log('成功:', res))
  5.   .catch(error => console.error('失败:', error)); // 失败: 第一个失败
  6. // p2 p1 交换位置,就会获得成功的结果
  7. Promise.race([p2, p1])
  8.   .then(res => console.log('成功:', res)) // 成功: 第二个成功
  9.   .catch(error => {
  10.     console.error('失败:', error)
  11.   });
复制代码
Promise.withResolvers()

2024 年新增的规范,使用时需注意兼容情况。
这方法相当于封装了一个语法糖,想比之前拥有了更简洁的代码逻辑而已,一般多用于跨模块共享 Promise 状态。使用方法:
  1. const { promise, resolve, reject } = Promise.withResolvers();
  2. function task() {
  3.   if (Math.random() > 0.5) {
  4.     return resolve('任务执行成功')
  5.   }
  6.   return reject(new Error('任务执行失败'))
  7. }
  8. task()
  9. promise.then(res => {
  10.   console.log('成功:', res)
  11. }).catch(err => {
  12.   console.error('失败:', err)
  13. })
复制代码
只是需要特别注意,promise 的状态在变为已解决或失败时,promise 的状态就无法再修改了,后面再调用 resolve 或 reject 方法都无任何响应。
这个静态方法可使用原有的方法实现,如下:
  1. function createDeferredPromise() {
  2.   let resolve, reject;
  3.   const promise = new Promise((res, rej) => {
  4.     resolve = res;
  5.     reject = rej;
  6.   });
  7.   return { promise, resolve, reject };
  8. }
  9. const { promise, resolve, reject } = createDeferredPromise();
复制代码
想比而言,withResolvers实现的代码更加简洁。
Promise.try()

这方法可时髦了,2025年才新增的规范,使用时需特别小心兼容性。
跟 try catch 相似,都是用于捕获异常,使用方法:
  1. console.log(1)
  2. Promise.try(() => {
  3.   console.log(3)
  4.   throw new Error('前端路引')
  5. }).catch(err => console.log('捕获:', err))
  6. console.log(2)
复制代码
执行顺序:
  1. 1
  2. 3
  3. 2
  4. 捕获: Error: 前端路引
复制代码
关于兼容性

由于 Promise 的静态方法都是在不同的 ES 版本迭代时添加进来的规范,所以多多少少都有一些兼容问题,在 Vite 项目中,可以使用以下两个插件来处理兼容问题:
1、@vitejs/plugin-legacy
周下载量在 35万左右
npm 地址:https://www.npmjs.com/package/@vitejs/plugin-legacy
2、vite-plugin-legacy-swc
周下载量再 1万左右
npm 地址:https://www.npmjs.com/package/vite-plugin-legacy-swc
使用方法可以参考 npm 的 Readme 文档。
写在最后

Promise 在处理异步任务时特别常用,还多用于一些耗时太长的任务场景,掌握 Promise 的使用,有利于编写出易于维护的项目代码。

来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除

相关推荐

您需要登录后才可以回帖 登录 | 立即注册