Skip to content

如何在 Vue.js 中使用 VueUse 中止 API 请求和处理错误

引言

在 Vue 应用程序中处理异步操作时,高效管理请求至关重要,特别是在处理可能长时间运行或不必要的请求时。在本文中,我们将探讨如何使用VueUse中止请求并处理这些被中止请求抛出的错误。

问题

在现代 Web 应用程序中,进行多个API 调用来获取数据是很常见的。然而,在某些情况下,我们可能想要取消正在进行的请求,例如当用户离开页面或当新请求取代现有请求时。此外,我们需要处理中止这些请求时可能发生的错误,以确保流畅的用户体验。

背景

VueUse 提供了一个强大的useFetch可组合函数,允许我们进行具有内置中止功能的 HTTP 请求。让我们看看如何利用这个特性:

typescript
const { abort, canAbort } = useFetch(url);

setTimeout(() => {
  if (canAbort.value) abort();
}, 100);

在这个例子中,我们可以使用useFetch提供的abort函数来中止请求。canAbort属性表示请求是否可以被中止。

我们还可以为中止请求设置自动超时:

typescript
const { data } = useFetch(url, { timeout: 100 });

这将在 100 毫秒后自动中止请求。

解决方案

现在,让我们实现一个解决方案,演示如何在Vue 组件中中止请求并处理错误。我们将创建一个获取消息的组件,并允许用户通过多次点击按钮来取消请求。

vue
<template>
  <div>
    <button @click="getMessages">获取消息</button>
    <div v-if="loading">加载中...</div>

    <ul v-else>
      <li v-for="message in messages" :key="message.id">
        {{ message.text }}
      </li>
    </ul>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { useFetch } from '@vueuse/core';
import { defineStore } from 'pinia';

interface Message {
  id: number;
  text: string;
}

const useStore = defineStore('main', {
  state: () => ({
    cancellableRequests: new Map<string, { abort: () => void }>(),
  }),
});

const store = useStore();

const messages = ref<Message[]>([]);
const loading = ref(false);

const getMessages = async (): Message[] => {
  try {
    loading.value = true;

    const url = '/api/messages';
    const token = 'getMessages';

    if (store.cancellableRequests.has(token)) {
      store.cancellableRequests.get(token)?.abort();
      store.cancellableRequests.delete(token);
    }

    const { execute, abort, data, error } = useFetch(url, {
      immediate: false,
    })
      .get()
      .json<{ messages: Message[] }>();

    store.cancellableRequests.set(token, { abort });

    await execute();

    if (error.value) {
      if error.value instanceof Error && error.value.name === 'AbortError') {
        store.cancellableRquests.delete(token);
        return []
      }

      throw new Error('出错了。请稍后再试。')
    }

    return data.value.messages;
  } finally {
    loading.value = false;
  }
};
</script>

在这个例子中,我们创建了一个 Vue 组件,演示如何中止请求并处理错误:

  1. 我们定义了一个Pinia存储来管理可取消的请求。
  2. getMessages函数负责获取消息并处理请求生命周期。
  3. 在发出新请求之前,我们检查是否存在具有相同令牌的现有请求,如果存在则中止它。
  4. 我们使用 VueUse 的useFetch来进行 API 调用。
  5. 我们将abort函数存储在 Pinia 存储中,允许我们在需要时取消请求。
  6. 我们处理错误,包括AbortError,这是在请求被取消时抛出的。
  7. 如果成功,我们返回获取的消息,如果请求被中止,则返回一个空数组。
  8. 最后,我们通过从存储中删除请求并将加载状态设置为 false 来进行清理。

这种实现允许高效管理 API 调用,防止不必要的网络请求,并改善整体用户体验。

结论

通过实施这个解决方案,我们成功地解决了最初的问题,即如何使用 VueUse 中止请求并处理它们抛出的错误。这种方法允许高效管理 API 调用,防止不必要的网络请求,并改善整体用户体验。