【Abort Controller】 优雅处理竞态请求

0 阅读3分钟

但行好事,莫问前程

前言

最近收到运营反馈 —— 订单列表在连续搜索时,经常出现数据失真的情况。

排查了下代码,发现是因为 没有处理竞态请求,这个问题很常见且因为接口延迟的原因,特别容易复现。

竞态请求 - 例如先发送查询请求A,然后切换发送查询请求B,(A,B属于同页面的同一接口,但条件不一样),如果A的响应比B慢,就会导致展示数据与预期内容不符。

image.png

本文会介绍如何使用 Abort Controller 解决竞态问题。

如果对你有所帮助,还望点赞、收藏、关注三连😽。

方案

整理一下思路,对这种连续请求导致的竞态场景,有哪些解决方法

  • 防抖、节流、loading
    • 直接有效的限制请求操作
    • 但无法根绝竞态的出现,且loading会存在阻塞用户操作的风险
  • canceltoken
    • axios 专用,局限性较大
    • 官方已推荐使用 AbortController 替代它
  • AbortController
    • JS 原生API,更现代的、标准的、更具通用性

所以更推荐使用 AbortController 优雅地处理 竞态请求 问题,避免数据错乱。

(最好让后端优化下接口😹)

AbortController

AbortController 是一个可以让你 主动取消异步操作 的浏览器API,已被主流浏览器(除IE)外所兼容。

QQ_1770107241635.png

它的使用方法如下:

  1. 构造函数

    new AbortController()

    创建一个新的 AbortController 对象实例。

  2. 实例属性

    controller.signal

    返回一个 AbortSignal 只读的对象实例,可以用它来和异步操作进行通信或者中止这个操作。

  3. 实例方法

    AbortController.abort()

    中止一个尚未完成的异步操作。这能够中止 fetch 请求及任何响应体和流的使用。

// 1. 创建一个控制器实例
const controller = new AbortController();

// 2. 将signal实例与请求绑定
fetch('/example', { signal: controller.signal })
.then((response) => response.json())
.catch(err => {})

// 3. 调用abort取消请求
setTimeout(() => { controller.abort() }, 1000);

实践

项目中,可以将单个控制器绑定在多个请求中(订单数据、交易数据、排名数据...),统一管控。

  const abortControllerRef = useRef<AbortController | null>(null);

  // 获取仪表板数据
  const getDashBoardData = (params: GetDashBoardP) => {
    // 取消未完成的请求,避免接口冲突
    abortControllerRef.current?.abort();
    abortControllerRef.current = new AbortController();
    const { signal } = abortControllerRef.current;
    
    setLoading(true);
    Promise.allSettled([
      getTransactionData(params, signal),
      getOrderData(params, signal),
      getRankData(params, signal)
    ])
      .catch(() => {})
      .finally(() => {
        setLoading(false);
      });
  }
  
  // 触发更新
  useEffect(() => {
    getDashBoardData(searchParams);
  }, [searchParams]);

总结

AbortController 是更现代的、标准的、更具通用性的竞态问题解决方案

适用场景,例如 组件卸载时清理请求、表格搜索、文件上传、清理事件监听

注意 请求还是会到服务端,abortcontroller 只是终止了前端的后续逻辑

在IE场景可以使用canceltoken

结语

不要光看不实践哦,希望本文能对你有所帮助。

持续更新前端知识,脚踏实地不水文,真的不关注一下吗~

写作不易,如果有收获还望 点赞+收藏 🌹

才疏学浅,如有问题或建议还望指教~