在前端开发中,批量请求可能会因为网络问题、服务器错误或权限问题而失败。如果每个失败的请求都弹出一个 Toast 提示,用户体验会很差。因此,我们需要确保在短时间内多个请求失败时,只显示一个 Toast 提示。

实现思路

  1. 维护一个全局状态,用于记录是否已经弹出 Toast。
  2. 使用节流函数throttle)或定时器,确保短时间内多个请求失败时,仅触发一次 Toast。
  3. 支持批量请求的全局错误拦截,如拦截 Axios 的响应错误,或者在 Fetch API 中封装统一的错误处理。

具体实现

1. 使用全局状态记录 Toast

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import axios from "axios";
import { message } from "antd";

// 定义一个全局状态,记录是否已经显示 Toast
let toastShown = false;

// 封装一个方法来显示 Toast,并设置定时器恢复状态
function showGlobalToast(msg: string) {
if (!toastShown) {
toastShown = true;
message.error(msg);
// 3秒后重置状态,允许下次错误时再次弹出 Toast
setTimeout(() => {
toastShown = false;
}, 3000);
}
}

// Axios 全局响应拦截器,捕获请求错误
axios.interceptors.response.use(
(response) => response,
(error) => {
showGlobalToast("请求失败,请稍后重试");
return Promise.reject(error);
}
);

// 示例批量请求
async function fetchBatchData() {
try {
await Promise.all([
axios.get("/api/data1"),
axios.get("/api/data2"),
axios.get("/api/data3"),
]);
} catch (error) {
console.error("批量请求发生错误", error);
}
}
  • 全局状态 toastShown:用来记录当前是否已经有 Toast 被弹出,避免在多个请求失败时重复弹出提示。
  • showGlobalToast 方法:在 Toast 未显示的情况下调用 message.error 弹出提示,并设置一个 3 秒的定时器,在定时器到期后将 toastShown 重置为 false,这样在下一次错误时可以重新弹出提示。
  • Axios 拦截器:捕获所有响应错误,并调用 showGlobalToast 方法,确保全局只有一次 Toast 弹出。

2. 使用 throttle 限制 Toast 触发频率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import axios from "axios";
import { message } from "antd"; // 使用 Antd 的 Toast 组件
import throttle from "lodash/throttle";

// 1. 创建一个节流的 Toast 方法,确保 3 秒内只弹一次
const showToast = throttle(
(msg: string) => {
message.error(msg);
},
3000,
{ leading: true, trailing: false }
);

// 2. Axios 全局错误拦截
axios.interceptors.response.use(
(response) => response,
(error) => {
showToast("请求失败,请稍后重试");
return Promise.reject(error);
}
);

// 示例批量请求
async function fetchBatchData() {
try {
await Promise.all([
axios.get("/api/data1"),
axios.get("/api/data2"),
axios.get("/api/data3"),
]);
} catch (error) {
console.error("批量请求发生错误", error);
}
}

throttle 确保 showToast 在 3 秒内最多执行一次,即使多个请求失败,也只会弹出一个 Toast。

优化

如何只限制文案相同的 Toast

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const messageTextSet: string[] = [];

const showToast = (msg: string) => {
if (!messageTextSet.includes(msg)) {
messageTextSet.push(msg)
message.error(msg);
setTimeout(() => {
const index = messageTextSet.findIndex((item) => item === msg);
if (index !== -1) {
messageTextSet.splice(index, 1);
}
}, 3000);
}
}

// 其余代码省略

通过在 messageTextSet 中临时存储将要提示的文案,如果命中则忽略,未命中的话就存入 messageTextSet,然后弹 Toast 提示,提示过后再从 messageTextSet 中删除刚刚提示的文案。