首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

如何避免旧请求的数据覆盖掉最新请求

编程知识
2024年09月14日 14:15

我的博客地址:如何避免旧请求的数据覆盖掉最新请求 - 蚊子的前端博客

在检索的场景中,经常会对同一个接口发起不同的检索条件的请求,若前一个请求响应较慢时,可能会覆盖掉我们后发起请求的结果。

如我们先发起一个搜索请求,参数是 A;这个请求还没结束,我们发起了参数是 B 的搜索请求;可能因网络原因或者后端服务处理等原因,后发起的参数 B 的请求先响应了,然后我们把数据展示到页面中;过一会儿之前发起参数是 A 的搜索请求也返回结果了。但实际上,参数 B 的响应结果,才是我们需要展示的最新的数据。

那么如何避免这种现象呢?

1. 请求锁定

可以对发起请求的按钮、输入框等,或者是在全局中,添加 loading,只有得到上一个请求的响应结果后,才取消 loading,才允许用户发起下一次的请求。

const App = () => {
  const [loading, setLoading] = useState(false);

  const request = async (data) => {
    if (loading) {
      // 若请求还没结束,则无法发起新的请求
      return;
    }
    setLoading(true);
    const result = await axios("/api", { data, method: "post" });
    setLoading(false);
  };

  return (
    <div className="app">
      <Form disabled={loading} onFinish={request}>
        <Form.Item>
          <Input />
        </Form.Item>
        <Button htmlType="submit" loading={loading}>
          搜索
        </Button>
      </Form>
    </div>
  );
};

直接用源头进行控制,根本不存在多个请求并行的情况,也就无所谓谁覆盖谁了。

2. 防抖

一般应用在纯输入框的搜索功能中,在用户停止输入一段时间后,才发起搜索,可以加大两次检索请求之间的时间间隔.

const App = () => {
  const request = async () => {};

  return (
    <div className="app">
      {/* 停止输入700ms后触发请求 */}
      <input onInput={debounce(request, 700)} />
    </div>
  );
};

防抖措施并不能完全杜绝数据被覆盖。假如上一次的请求确实很慢,那也会出现覆盖后续请求的现象。

3. 取消上次的请求

当需要发起新的请求,上次的请求还没结束时,可以取消上次请求。

const App = () => {
  const cancelSouceRef = useRef(null);

  const request = async () => {
    if (cancelSouceRef.current) {
      // 若存在上次的请求还没结束,则手动取消
      cancelSouceRef.current.cancel("手动取消上次的请求");
    }
    const source = axios.CancelToken.source();
    cancelSouceRef.current = source;

    try {
      const response = await axios.get("/api/data", {
        cancelToken: source.token,
      });
      setData(response.data);
    } catch (error) {
      if (axios.isCancel(error)) {
        console.log("请求被取消", error.message);
      } else {
        console.log("请求出错", error.message);
      }
    } finally {
      cancelSouceRef.current = null;
    }
  };

  return (
    <div className="app">
      <button onClick={request}>请求</button>
    </div>
  );
};

如果服务端已接收到了请求,不论前端是否取消了请求,服务端都会完整查询并返回,只是浏览器不再处理而已。

4. 时序控制

我们在每次请求时,都给该请求一个唯一标识,并在该组件的全局中保存最新的标识,若响应时的标识表示最新的标识,则不处理该响应的结果。

标识只要在当前组件中唯一即可,如自增数字、时间戳、随机数等,都可以。

const App = () => {
  const requestIdRef = useRef(0); // 保存最新的请求id

  const request = async () => {
    requestIdRef.current++; // 每次自增

    const curRequestId = requestIdRef.current;
    try {
      const response = await axios.get("/api/data", {
        cancelToken: source.token,
      });
      if (curRequestId < requestIdRef.current) {
        // 当前请求不是最新的,不做任何处理
        return;
      }
      setData(response.data);
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <div className="app">
      <button onClick={request}>请求</button>
    </div>
  );
};

这是一种比较简单有效,同时能让用户任意搜索的方案。

5. 总结

当然,在实际中,肯定也是多方案的组合。比如纯输入框触发搜索的场景中,一般是防抖+时序控制的两种方案的组合,既能减少触发请求的次数,又能避免数据的相互覆盖。

有的同学可能想到「控制请求的并发数量」,用队列递归等方式,每次将发起的请求都放到队列的后面,然后按照队列的顺序发起请求。如我们之前曾经在文章 JavaScript 中的 Promise 异步并发控制 探讨过这种场景。

这种方式倒也能解决问题,不过有种「杀鸡用牛刀」的感觉。因为在现在的场景中,对同一个接口发起多次请求时,其实我们更关心的是最新请求的结果,之前请求的结果直接可以扔掉了。

欢迎关注我的公众号:前端小茶馆。

前端小

From:https://www.cnblogs.com/xumengxuan/p/18414021
本文地址: http://www.shuzixingkong.net/article/2019
0评论
提交 加载更多评论
其他文章 Nuxt Kit 自动导入功能:高效管理你的模块和组合式函数
title: Nuxt Kit 自动导入功能:高效管理你的模块和组合式函数 date: 2024/9/14 updated: 2024/9/14 author: cmdragon excerpt: 通过使用 Nuxt Kit 的自动导入功能,您可以更高效地管理和使用公共函数、组合式函数和 Vue A
Nuxt Kit 自动导入功能:高效管理你的模块和组合式函数 Nuxt Kit 自动导入功能:高效管理你的模块和组合式函数
手撸MQ消息队列——循环数组
队列是咱们开发中经常使用到的一种数据结构,它与栈的结构类似。然而栈是后进先出,而队列是先进先出,说的专业一点就是FIFO。在生活中到处都可以找到队列的,最常见的就是排队,吃饭排队,上地铁排队,其他就不过多举例了。 队列的模型 在数据结构中,和排队这种场景最像的就是数组了,所以我们的队列就用数组去实现
手撸MQ消息队列——循环数组 手撸MQ消息队列——循环数组 手撸MQ消息队列——循环数组
45岁大龄程序员自述:我居然还苟在程序人生里,但是已经难以为继
世界那么大,我想去看看... 原文 不会打歌么学打歌阿哥怎摆你怎摆,大江大海江大海 ... 瞧,这个中年不油腻(不油腻的原因是大叔很穷)的大叔扛着音箱出场了,其实远没有这么拉风! 今年被动看到许多不好的消息和内容:充满了“失业”,“裁员”等。一度我已经更郁郁了。所以我今天不是来搞笑的。真心希望大家能
45岁大龄程序员自述:我居然还苟在程序人生里,但是已经难以为继 45岁大龄程序员自述:我居然还苟在程序人生里,但是已经难以为继
推荐3款卓越的 .NET 开源搜索组件库
前言 最近有不少同学提问;.NET有哪些开源的搜索组件库可以推荐的吗?,今天大姚给大家推荐3款卓越的 .NET 开源搜索组件库,希望可以帮助到有需要的同学。 Elasticsearch .NET Elasticsearch 的 .NET 客户端为 Elasticsearch API 提供强类型请求和
推荐3款卓越的 .NET 开源搜索组件库 推荐3款卓越的 .NET 开源搜索组件库 推荐3款卓越的 .NET 开源搜索组件库
docker安装运行kafka单机版
这里我们安装一下kafka的单机版,由于kafka是基于zk进行管理的,如果我们没有安装过zk的话,需要进行安装好zk再安装kafka,当然如果已经安装过了, 那就没必要安装了。我们可以执行docker images命令查看我们的zk镜像是否已经存在了。执行的主要的流程如下所示: 1. docker
OpenSSL证书通过Subject Alternative Name扩展字段扩展证书支持的域名
1、概述 1.1 什么是Subject Alternative Name(证书主体别名) SAN(Subject Alternative Name) 是 SSL 标准 x509 中定义的一个扩展。它允许一个证书支持多个不同的域名。通过使用SAN字段,可以在一个证书中指定多个DNS名称(域名)、IP地
OpenSSL证书通过Subject Alternative Name扩展字段扩展证书支持的域名 OpenSSL证书通过Subject Alternative Name扩展字段扩展证书支持的域名 OpenSSL证书通过Subject Alternative Name扩展字段扩展证书支持的域名
全能还是专精?关于技术通才与技术专家的思考
在日新月异的 IT 行业中,每隔数年乃至数月,便会涌现出革新性的技术或前沿框架,引领行业潮流。 比如前端开发,我刚开始工作时,大部分都是静态页面+JavaScript,页面上只有一些简单的交互。 后来出现了Ajax技术和JQuery库,现在想起当年第一次使用JQuery时,真的觉得这就是前端库的终点
全能还是专精?关于技术通才与技术专家的思考
小李移动开发成长记 —— 大话小程序
小李移动开发成长记 —— 大话小程序 做传统网站前端开发的同学初次接触小程序,会有许多困惑:为什么没有div,view 是什么、怎么没有 ajax,wx.request 为什么是回调方式、预览怎么要用小程序开发者工具、APPID有什么用、安装npm包怎么还要构建、tabBar 是什么、语法怎么和vu
小李移动开发成长记 —— 大话小程序