前端axios fetch 解决接口请求响应数据返回快慢不均导致的数据错误问题

引言

搜索功能,我想很多业务都会涉及,这个功能的特点是:

  • 用户可以在输入框中输入一个关键字,然后在一个列表中显示该关键字对应的数据;
  • 输入框是可以随时修改/删除全部或部分关键字的;
  • 如果是实时搜索🔍(即输入完关键字马上出结果,不需要额外的操作或过多的等待),接口调用将会非常频繁。

实时搜索都会面临一个通用的问题,就是:

浏览器请求后台接口都是异步的,如果先发起请求的接口后返回数据,列表/表格中显示的数据就很可能会是错乱的。 

 会引发的bug如下:

搜索的时候,连续快速输入或者删除关键字,搜索结果和搜索关键字不匹配。

问题分析:

  1. 浏览器从服务器发起的请求都是异步的;
  2. 由于前一次请求服务器返回比较慢,还没等第一次请求返回结果,后一次请求就发起了,并且迅速返回了结果,这时表格肯定显示后一次的结果;
  3. 过了2秒,第一次请求的结果才慢吞吞地返回了,这时表格错误地又显示了第一次请求的结果;
  4. 最终导致了这个bug。

怎么解决呢?

在想解决方案之前,得想办法必现这个问题,靠后台接口是不现实的,大部分情况下后台接口都会很快返回结果。

所以要必现这个问题,得先模拟慢接口。

模拟慢接口,请参考另一篇文章

取消慢接口请求

能模拟慢接口,就能轻易地必现测试提的问题啦!

先必现这个问题,然后尝试修复这个问题,最后看下这个问题还出不出现,不出现说明我们的方案能解决这个bug,问题还有说明我们得想别的办法。

fetch

先来看下 fetch,fetch 是浏览器原生提供的 AJAX 接口,使用起来也非常方便。

使用 fetch 发起一个 post 请求:

fetch('http://localhost:3000/getList', {
   method: 'POST',
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  },
  body: JSON.stringify({
    id: 1
  })
}).then(result => {
  console.log('result', result);
});

 可以使用 AbortController 来实现请求取消:

this.controller?.abort(); // 重新发起 http 请求之前,取消上一次请求
 
const controller = new AbortController(); //  创建 AbortController 实例
const signal = controller.signal;
this.controller = controller;
 
fetch('http://localhost:3000/getList', {
   method: 'POST',
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  },
  body: JSON.stringify({
    id: 1
  }),
  signal, // 信号参数,用来控制 http 请求的执行
}).then(result => {
  console.log('result', result);
});

fetch请求补充说明:

  • 尽量在单独的请求方法中添加,如果放在公用请求库里处理,会出现其它pedding中的接口也被取消了
  • 放在单独的请求方法中,export方法不能使用default

axios

再来看看 axios,先看下如何使用 axios 发起 post 请求。

发起post请求

axios.post('http://localhost:3000/getList', {
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  },
  data: {
    id: 1,
  },
})
.then(result => {
  console.log('result:', result);
});

axios 发起的请求可以通过 cancelToken 来取消。

this.source?.cancel('The request is canceled!');
 
this.source = axios.CancelToken.source(); // 初始化 source 对象
 
axios.post('http://localhost:3000/getList', {
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  },
  data: {
    id: 1,
  },
}, { // 注意是第三个参数
  cancelToken: this.source.token, // 这里声明的 cancelToken 其实相当于是一个标记或者信号
})
.then(result => {
  console.log('result:', result);
});

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值