面试官:在连续请求过程中,如何取消上次的请求?

前言

这个问题想必很多朋友都遇到过,我再详细说一下场景!

如 Boss 搜索框所示:

先输入1
再输入2
再输入3
再输入123
请求参数依次为:1 12 123 123123

请求参数通过右侧的 query 参数也可以看到,一共请求了四次。

不难发现,这里已经做了基本的防抖,因为我们连续输入123的时候,只发了一次请求。

好了,现在看完基本场景,我们回到正题!

从上面的演示中不难发现我们一共发送了4次请求,顺序依次为1、12、123、123123。

问题

面试官现在问题如下:

我先输入的 1,已经发送请求了,紧接着输入了 2,3,123,如果在我输入最后一次 123 的时候,我第一次输入的 1 还没有请求成功,那请求 query 为 1 的这个接口将会覆盖 query 为 123123 的搜索结果,因为当 1 成功的时候会将最后一次请求的结果覆盖掉,当然这个概率很小很小,现在就这个bug,说一下你的解决思路吧!

解决

看到这个问题我们首先应该思考的是如何保证后面的请求不被前面的请求覆盖掉,首先说一下防抖是不行的,防抖只是对连续输入做了处理,并不能解决这个问题,上面的演示当中应该不难发现。

如何保证后面的请求不被前面的请求覆盖掉?

我们思路是否可以转化为:只需要保证后面的每次接口请求都是最新的即可?

简单粗暴一点就是,我们后续请求接口时直接把前面的请求干掉即可!

那如何在后续请求时,直接干掉之前的请求?

关键:使用 AbortController

MDN 解释如下:

AbortController 接口表示一个控制器对象,允许你根据需要中止一个或多个 Web 请求。

AbortController.abort(),中止一个 尚未完成 的 Web(网络)请求。

MDN 文档如下:

AbortController - Web API 接口参考 | MDN (mozilla.org)

我们可以借助 AbortController 直接终止还 未完成 的接口请求,注意这里说的是还未完成的接口,如果接口已经请求成功就没必要终止了。

代码实现

参考代码如下:

js 复制代码
    let currentAbortController = null;
    function fetchData(query) {
      // 取消上一次未完成的请求
      if (currentAbortController) {
        currentAbortController.abort();
      }

      // 创建新的 AbortController
      currentAbortController = new AbortController();

      return fetch(`/api/search?q=${query}`, {
        signal: currentAbortController.signal
      })
      .then(response => response.json())
      .then(data => {
        // 处理请求成功的数据
        updateDropdownList(data);
      })
      .catch(error => {
        // 只有在请求未被取消的情况下处理错误
        if (!error.name === 'AbortError') {
          handleError(error);
        }
      });
    }

借用官方的解释:

fetch 请求初始化时,我们将 AbortSignal 作为一个选项传递进入请求的选项对象中(下面的 {signal: currentAbortController.signal})。这将 signal 和 controller 与 fetch 请求相关联,并且允许我们通过调用 AbortController.abort() 去中止它!

这就意味着我们将 signal 作为参数进行传递,当我们调用 currentRequest.abort() 时就可以终止还未完成的接口请求,从而达到我们的需要。

我们在每次重新调用这个接口时,判断是否存在 AbortController 实例,如果存在直接中止掉该实例即可,这样就可以保证我们每次的请求都可以拿到最新的数据。

js 复制代码
    if (currentAbortController) {
        currentAbortController.abort();
      }

总结

我们再来理一下这个逻辑:

首先是第一次调用时为接口请求添加 AbortSignal 参数

之后在每次进入都判断是否存在 AbortController 实例,有的话直接取消掉

取消只会针对还未完成的请求,已经完成的不会取消

通过这样就可以达到我们每次都会使用最新的请求接口作为数据来源,因为后面的接口会将前面的干掉

如果这道面试题这样回答,是不是还不错?

相关推荐
暗不需求2 分钟前
# 深入 React Todos:从零实现一个状态提升与本地持久化的待办应用
javascript·react.js·全栈
DFT计算杂谈6 分钟前
自动化脚本一键绘制三元化合物相图
java·运维·服务器·开发语言·前端·python·自动化
子兮曰9 分钟前
深入 Superpowers:180k Stars 的开源 AI 编程方法论是如何工作的
前端·javascript·后端
沸点小助手22 分钟前
「新晋AI顶流PK:GPT-5.5 vs DeepSeek V4&掘友吐槽小会」沸点获奖名单公示|本周互动话题上新🎊
前端·人工智能
隔壁的大叔31 分钟前
Markdown 渲染如何穿插自定义组件
前端·javascript·vue.js
Rik37 分钟前
用 AI Skill 封装你的工作流:从代码规范到全流程提效实战
前端·后端
薯老板39 分钟前
JavaScript原型,原型链
javascript
Dabei41 分钟前
Android TV 焦点处理详解:遥控器与空鼠
android·前端
愚者Pro1 小时前
Flutter基础学习
前端·javascript·vue.js
ZC跨境爬虫1 小时前
跟着 MDN 学 HTML day_17:媒体与 Web Audio API 自动播放指南——策略、检测与最佳实践
前端·笔记·ui·html·音视频·媒体