【面试官】:如何解决多个请求失败后重复弹窗报错

在项目开发中,一个页面经常会有多个接口请求。正常情况下,接口请求正常,然后各自处理自己的回调函数即可。但是如果因为网络或者其他原因,这些请求触发了错误回调,就可能会有多个message提示同时出现的情况。

解决思路

先分析一下问题,我们其实只能更合理地处理这种类似问题,但是没有很完美的处理方式。下面有几个思路我先列出来,然后看看有没有什么问题。

  1. 合并错误提示:我们可以将同一时间(例如在很短的时间间隔内)发生的多个错误合并成一个错误提示,告诉用户有多个错误发生。
  2. 使用队列和防抖:将错误提示放入一个队列中,然后使用防抖(debounce)或节流(throttle)技术来延迟显示,并在延迟时间内合并相同的错误或不同的错误,最后统一显示一个错误提示。
  3. 优先级提示:如果错误有优先级,比如有些错误更重要,那么我们可以只显示最高优先级的错误。
  4. 避免重复错误:有时候多个错误可能是同一个原因导致的,我们可以通过错误信息去重,避免显示重复的错误。

分析:

四点!其实无非两个思路。即合并和优先级

对于第一个解决办法,合并 。它其实是在设定好的一定时间内将所有的错误信息收集起来,然后集中提示出来。这种方式的问题是,如果同一个页面的请求有些需要耗时特别长,超过了设定的时间。那么合并就会将其漏掉,如果一味地加时长,那么可能错误提示还出来,就因为长时间白屏或者数据为空,用户已经离开了,造成的用户体验非常差。

对于第二种,优先级。首先它同样会有设定时间段的问题,即上面合并的缺点。因为要显示高优先级错误就势必要先收集有哪些并发的请求,不过同一个优先级怎么办呢?这种时候也许会按照最后一个来提示?那么其他同样高优先级的怎么办?没有看到,无法处理,只能一个个处理完了才能接着下一个(当然是用户需要处理的情况下,很多时候其实不需要用户来处理)

尝试处理

合并处理

定义一个收集错误信息队列的类:

kotlin 复制代码
// 错误管理器(单例模式)
class ErrorManager {
  constructor() {
    this.errorQueue = []
    this.debounceTimer = null
    this.debounceDelay = 500 // 500ms内错误合并
  }

  pushError(error) {
    this.errorQueue.push(error)
    if (!this.debounceTimer) {
      this.debounceTimer = setTimeout(() => this.flushErrors(), this.debounceDelay)
    }
  }

  flushErrors() {
    if (this.errorQueue.length === 0) return

    // 合并错误信息
    const uniqueErrors = [...new Set(this.errorQueue)]
    const message = uniqueErrors.length > 1 
      ? `${uniqueErrors.length}项操作失败,请检查` 
      : uniqueErrors[0]

    // 显示UI提示(示例使用antd)
    notification.error({
      message: '操作失败',
      description: message,
      duration: 3
    })

    // 重置状态
    this.errorQueue = []
    this.debounceTimer = null
  }
}

再来是全局处理:

vbscript 复制代码
// 使用示例(在请求拦截器中)
const errorManager = new ErrorManager()

// 这里仅仅用了error回调来举例,其实我们有些业务上的错误也可以这样做的,只不过放在response里处理即可
axios.interceptors.response.use(
  response => response,
  error => {
    const errorMsg = error.response?.data?.message || '请求失败'
    errorManager.pushError(errorMsg)
    return Promise.reject(error)
  }
)

这里做了一个优化,因为这些错误信息很可能是相同的,所以用Set()做了一下去重。避免相同的信息反复呈现。

优先级

优先级这里不想做的那么复杂,反正既然就算有优先级也可能会有相同优先级的一起出现,不如化整为零,都默认一样的优先级。当然这里如果有特殊要求,最好按照需求来。

最终处理起来很简单了:

scss 复制代码
let activeError = null

function showError(msg) {
  if (activeError) activeError.destroy() // 关闭前一个提示
  activeError = message.error(msg)
}

ElementUI的话就是这样:

javascript 复制代码
import { Message } from 'element-ui'

let currentMessage = null
const messageToast = (options) => {
  if (messageUse) {
    currentMessage.close()
  }
  currentMessage = Message(options)
}

export default messageToast

核心原则:减少视觉干扰,提升信息密度(合并信息)

至于UI怎么显示的话,看具体需求,我倒是认为可以做一些区分,比如errorQueue里面只有一条错误信息,就用Message来提示,简便,但是如果有多条,则可以用Notification侧边通知这种。根据UI设计的统一规范来即可。

结论

可以将合并操作和关闭旧提示两个操作合二为一,达到一个相对合理的处理多个弹窗同时出现的应对方式

相关推荐
豆苗学前端4 分钟前
vue3+TypeScript 实现一个图片占位符生成器
前端·面试·github
neon12045 分钟前
Vue 3 父子组件通信核心机制详解:defineProps、defineEmits 与 defineExpose 完全指南
前端·javascript·vue.js·前端框架
Ciito11 分钟前
vue+moment将分钟调整为5的倍数(向下取整)
javascript·vue.js
Juchecar22 分钟前
Vue3 开发环境搭建及循序渐进学习指南
前端·javascript
Data_Adventure38 分钟前
@scqilin/phone-ui手机外观组件库
前端
一点一木1 小时前
Vue Vapor 事件机制深潜:从设计动机到源码解析
前端·vue.js·vapor
FSHOW1 小时前
记一次开源_大量SVG的高性能渲染
前端·react.js
小牛.7931 小时前
Web第二次作业
前端·javascript·css
二闹1 小时前
都2025了还要用Layui做下拉控件-我只能说你有水平
前端
Pikachu8031 小时前
揭秘 tyarn:一个为大型 TypeScript Monorepo 优化的 Yarn 性能猛兽
前端·javascript