请求失败会弹出一个 toast,如何保证批量请求失败,只弹出一个 toast

44 阅读3分钟

声明:以下答案均为 deepSeep 输出

方法一:标志位控制

  • 标志位控制:通过 hasToastShown 确保 toast 只弹出一次。
  • 统一错误处理:使用 Promise.all 处理批量请求,在 catch 中统一处理错误并弹出 toast。
  • 重置标志位:在 finally 中重置标志位,以便下次请求可以再次弹出 toast
let hasToastShown = false;

function showToast(message) {
  if (!hasToastShown) {
    // 弹出 toast
    Toast.show(message);
    hasToastShown = true;
  }
}

function handleBatchRequests(requests) {
  Promise.all(requests)
    .then(responses => {
      // 处理成功响应
    })
    .catch(error => {
      showToast("请求失败,请稍后重试");
    })
    .finally(() => {
      // 重置标志位
      hasToastShown = false;
    });
}

方法二:防抖

通过防抖,将多次请求失败合为一次处理,确保在一定时间内只弹出一个 toast。

实现思路:

  • 设置一个防抖函数,延迟执行toast弹出。
  • 如果在延迟时间内有新的失败请求,取消之前的延迟并重新计时。
let toastTimeout = null;

function showToast(message) {
  if (toastTimeout) {
    clearTimeout(toastTimeout); // 取消之前的延迟
  }
  toastTimeout = setTimeout(() => {
    Toast.show(message); // 弹出 toast
    toastTimeout = null; // 重置计时器
  }, 300); // 设置防抖时间(例如 300ms)
}

function handleBatchRequests(requests) {
  Promise.all(requests)
    .then(responses => {
      // 处理成功响应
    })
    .catch(error => {
      showToast("请求失败,请稍后重试");
    });
}

方法三:队列管理

将失败请求放入队列中,统一处理队列中的失败请求,确保只弹出一个 toast。

实现思路:

  • 维护一个失败请求队列。
  • 当队列不为空时,弹出toast并清空队列。
let failedRequestsQueue = [];

function showToast(message) {
  if (failedRequestsQueue.length > 0) {
    Toast.show(message); // 弹出 toast
    failedRequestsQueue = []; // 清空队列
  }
}

function handleBatchRequests(requests) {
  Promise.all(requests)
    .then(responses => {
      // 处理成功响应
    })
    .catch(error => {
      failedRequestsQueue.push(error); // 将失败请求加入队列
      showToast("请求失败,请稍后重试");
    });
}

方法四:单例模式

  • 创建一个单例的 toast 管理器,负责控制 toast 的弹出。
  • 在批量请求失败时,调用单例管理器弹出 toast 。
class ToastManager {
  constructor() {
    this.isToastShown = false;
  }

  showToast(message) {
    if (!this.isToastShown) {
      Toast.show(message);
      this.isToastShown = true;
      setTimeout(() => {
        this.isToastShown = false; // 重置状态
      }, 3000); // 假设 toast 显示时间为 3 秒
    }
  }
}

const toastManager = new ToastManager();

function handleBatchRequests(requests) {
  Promise.all(requests)
    .then(responses => {
      // 处理成功响应
    })
    .catch(error => {
      toastManager.showToast("请求失败,请稍后重试");
    });
}

方法五:全局状态管理

如果项目中使用状态管理工具(如 Redux、Vuex 等),可以通过全局状态控制 toast 的弹出。

实现思路:

  • 在全局状态中维护一个 hasToastShown 状态。
  • 在请求失败时,检查状态并决定是否弹出 toast。
// Action
function showToast(message) {
  return (dispatch, getState) => {
    const { hasToastShown } = getState();
    if (!hasToastShown) {
      dispatch({ type: "SHOW_TOAST", payload: message });
      dispatch({ type: "SET_TOAST_SHOWN", payload: true });
      setTimeout(() => {
        dispatch({ type: "SET_TOAST_SHOWN", payload: false }); // 重置状态
      }, 3000); // 假设 toast 显示时间为 3 秒
    }
  };
}

// Reducer
const initialState = {
  hasToastShown: false,
};

function toastReducer(state = initialState, action) {
  switch (action.type) {
    case "SET_TOAST_SHOWN":
      return { ...state, hasToastShown: action.payload };
    default:
      return state;
  }
}

// 请求处理
function handleBatchRequests(requests) {
  Promise.all(requests)
    .then(responses => {
      // 处理成功响应
    })
    .catch(error => {
      store.dispatch(showToast("请求失败,请稍后重试"));
    });
}

方法六:Promise 最终状态

在批量请求完成后,统一检查是否有失败请求,并弹出 toast。

实现思路:

  • 使用 Promise.allSettled 获取所有请求的最终状态。
  • 检查是否有失败的请求,并弹出 toast。
function handleBatchRequests(requests) {
  Promise.allSettled(requests)
    .then(results => {
      const hasFailed = results.some(result => result.status === "rejected");
      if (hasFailed) {
        Toast.show("请求失败,请稍后重试");
      }
    });
}

总结

方法优点缺点
标志位控制简单直接,易于实现需要手动重置标志位
防抖避免短时间内多次弹出 toast需要设置合理的防抖时间
队列管理灵活,适合复杂场景需要额外维护队列
单例模式确保全局唯一性,适合大型项目需要额外实现单例逻辑
全局状态管理适合使用状态管理的项目依赖状态管理工具
Promise 最终状态简单,适合批量请求的统一处理无法实时响应失败请求