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

前言

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

如 Boss 搜索框所示:

先输入1

再输入2

再输入3

再输入123 

请求参数依次为:1 12 123 123123

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

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

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

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

面试官现在问题如下:

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

解决

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

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

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

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

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

使用 AbortController 

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

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

MDN 解释如下:

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

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

代码实现

代码如下:

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() 时就可以终止还未完成的接口请求,从而达到我们的需要。

总结

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

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

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

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

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

如果这道面试题这样给面试官回答,是不是很不错?

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你可以使用axios提供的取消请求的功能来取消上次请求送当前请求。首先,你需要创建一个取消令牌(cancel token),然后将其传递给你的请求。当你想要取消请求时,只需调用取消令牌的cancel方法。 以下是一个示例代码: ```javascript import axios from 'axios'; // 创建取消令牌 const cancelTokenSource = axios.CancelToken.source(); // 请求 axios.get('https://api.example.com/data', { cancelToken: cancelTokenSource.token }) .then(response => { // 处理响应数据 console.log(response.data); }) .catch(error => { if (axios.isCancel(error)) { // 请求取消 console.log('请求取消', error.message); } else { // 处理其他错误 console.log('请求生错误', error.message); } }); // 取消上次请求送当前请求 cancelTokenSource.cancel('取消上次请求'); // 送当前请求 axios.get('https://api.example.com/new-data', { cancelToken: cancelTokenSource.token }) .then(response => { // 处理响应数据 console.log(response.data); }) .catch(error => { if (axios.isCancel(error)) { // 请求取消 console.log('请求取消', error.message); } else { // 处理其他错误 console.log('请求生错误', error.message); } }); ``` 在这个示例,我们首先创建了一个取消令牌cancelTokenSource,并将其传递给第一个请求。然后,我们调用cancelTokenSource的cancel方法来取消上次请求,并送当前请求。在请求的then和catch方法,我们可以根据axios.isCancel方法来判断请求是否被取消,并进行相应的处理。 希望这个示例对你有帮助!如果你有任何其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JacksonChen_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值