返回

Vue.js 中 Promise.allSettled 不执行?

vue.js

Vue.js 中 Promise.allSettled 不执行?异步操作陷阱及解决方案

你是否遇到过在 Vue.js 中使用 Promise.allSettled 时,代码逻辑没有按照预期执行的情况?你可能会困惑为什么 Promise.allSettled 没有等待所有 Promise 完成就继续执行了。别担心,你并不是唯一一个。本文将深入浅出地解释这个问题背后的原因,并提供清晰易懂的解决方案,帮助你轻松驾驭异步操作。

异步操作:JavaScript 的幕后工作者

在深入探讨 Promise.allSettled 之前,让我们先来了解一下 JavaScript 中异步操作的本质。

想象一下餐厅点餐的场景:你点了一份牛排,服务员会给你一张点菜单,然后转身去处理其他订单。你不会傻傻地一直盯着服务员,直到牛排做好才点下一道菜,对吧?

JavaScript 中的异步操作就像餐厅点餐一样。当你发起一个网络请求时,JavaScript 引擎不会停下来等待服务器响应。相反,它会将这个请求交给浏览器处理,自己则继续执行后面的代码。

Promise:异步操作的“承诺”

为了管理异步操作,JavaScript 引入了 Promise。Promise 就像一个承诺,它代表了一个未来可能完成的操作。它有三种状态:

  • Pending(进行中): 操作尚未完成。
  • Fulfilled(已完成): 操作成功完成。
  • Rejected(已拒绝): 操作失败。

你可以使用 .then() 方法来监听 Promise 的完成状态,并根据结果执行相应的操作。

Promise.allSettled:掌握所有 Promise 的命运

Promise.allSettled 方法接收一个 Promise 数组,并返回一个新的 Promise。这个新的 Promise 会在所有传入的 Promise 都完成时才完成,无论它们是成功还是失败。

需要强调的是,Promise.allSettled 不会改变传入 Promise 的执行顺序或方式。 它就像一位尽职尽责的管家,默默观察着所有 Promise 的状态,并在它们都尘埃落定时向你汇报。

代码分析:揪出问题的“罪魁祸首”

让我们来分析一下你的代码。你定义了两个 Promise:loadFilesPromisegetBucketAccessPromise,分别用于加载文件和获取存储桶访问权限。然后,你使用 Promise.allSettled 来等待这两个 Promise 完成。

然而,问题就出在 loadFilesPromise 的定义上:

loadFilesPromise = this.loadFiles()

你直接调用了 this.loadFiles() 方法,并将返回值赋给了 loadFilesPromise。这意味着在执行到 Promise.allSettled 时,loadFilesPromise 已经是一个 resolved 的 Promise 了,因为它保存的是 this.loadFiles() 的执行结果,而不是 this.loadFiles() 返回的 Promise 对象。

这就是为什么 Promise.allSettled 没有等待 loadFilesPromise 的原因!

解决方案:延迟 Promise 的执行

要解决这个问题,我们需要确保 loadFilesPromisegetBucketAccessPromisePromise.allSettled 中被使用时才开始执行。

一种简单的方法是将 Promise 的创建逻辑移到 Promise.allSettled 内部:

Promise.allSettled([
  // 在这里创建 Promise,确保在需要时才执行
  () => this.loadFiles(), 
  () => new Promise((resolve, reject) => {
    axios.post('getBucketAccess', {
      username: '_self_'
    })
    .then(res => {
      console.log('Promise 2');
      // ... other logic ...
      resolve(res); // 确保 Promise 正确地 resolve
    })
    .catch(error => reject(error))
  })
])
.then(results => {
  console.log('FINISH ALL');
  console.log(results);
  this.$store.commit('setLoadingBucket', false);
})
.catch(error => {
  console.log('asdasdasdasdasdasdasd');
  // 处理错误
});

通过将 this.loadFiles()new Promise(...) 包裹在一个函数中,我们延迟了它们的执行时间,确保它们只在 Promise.allSettled 开始执行时才创建 Promise 对象。

常见问题解答

1. 为什么我需要使用 Promise.allSettled 而不是 Promise.all

Promise.all 会在任何一个传入的 Promise 被拒绝时立即拒绝,而 Promise.allSettled 会等待所有 Promise 完成,无论它们是成功还是失败。如果你需要获取所有 Promise 的结果,无论它们的状态如何,那么应该使用 Promise.allSettled

2. 我应该在什么时候使用异步操作?

当你需要执行一些耗时的操作,例如网络请求、文件读写等,为了避免阻塞主线程,影响用户体验,应该使用异步操作。

3. 如何处理异步操作中的错误?

可以使用 .catch() 方法来捕获 Promise 拒绝时的错误信息。

4. async/await 和 Promise 有什么区别?

async/await 是一种更简洁、更易读的异步编程语法糖,它可以让你像编写同步代码一样编写异步代码。

5. 我还有其他问题!

欢迎在评论区留言,我会尽力解答!