- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
我的博客地址:如何避免旧请求的数据覆盖掉最新请求 - 蚊子的前端博客 。
在检索的场景中,经常会对同一个接口发起不同的检索条件的请求,若前一个请求响应较慢时,可能会覆盖掉我们后发起请求的结果.
如我们先发起一个搜索请求,参数是 A;这个请求还没结束,我们发起了参数是 B 的搜索请求;可能因网络原因或者后端服务处理等原因,后发起的参数 B 的请求先响应了,然后我们把数据展示到页面中;过一会儿之前发起参数是 A 的搜索请求也返回结果了。但实际上,参数 B 的响应结果,才是我们需要展示的最新的数据.
那么如何避免这种现象呢?
可以对发起请求的按钮、输入框等,或者是在全局中,添加 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>
);
};
直接用源头进行控制,根本不存在多个请求并行的情况,也就无所谓谁覆盖谁了.
一般应用在纯输入框的搜索功能中,在用户停止输入一段时间后,才发起搜索,可以加大两次检索请求之间的时间间隔. 。
const App = () => {
const request = async () => {};
return (
<div className="app">
{/* 停止输入700ms后触发请求 */}
<input onInput={debounce(request, 700)} />
</div>
);
};
但防抖措施并不能完全杜绝数据被覆盖。假如上一次的请求确实很慢,那也会出现覆盖后续请求的现象.
当需要发起新的请求,上次的请求还没结束时,可以取消上次请求.
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>
);
};
如果服务端已接收到了请求,不论前端是否取消了请求,服务端都会完整查询并返回,只是浏览器不再处理而已.
我们在每次请求时,都给该请求一个唯一标识,并在该组件的全局中保存最新的标识,若响应时的标识表示最新的标识,则不处理该响应的结果.
标识只要在当前组件中唯一即可,如自增数字、时间戳、随机数等,都可以.
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>
);
};
这是一种比较简单有效,同时能让用户任意搜索的方案.
当然,在实际中,肯定也是多方案的组合。比如纯输入框触发搜索的场景中,一般是防抖+时序控制的两种方案的组合,既能减少触发请求的次数,又能避免数据的相互覆盖.
有的同学可能想到「控制请求的并发数量」,用队列,递归等方式,每次将发起的请求都放到队列的后面,然后按照队列的顺序发起请求。如我们之前曾经在文章 JavaScript 中的 Promise 异步并发控制 探讨过这种场景.
这种方式倒也能解决问题,不过有种「杀鸡用牛刀」的感觉。因为在现在的场景中,对同一个接口发起多次请求时,其实我们更关心的是最新请求的结果,之前请求的结果直接可以扔掉了.
欢迎关注我的公众号:前端小茶馆.
最后此篇关于如何避免旧请求的数据覆盖掉最新请求的文章就讲到这里了,如果你想了解更多关于如何避免旧请求的数据覆盖掉最新请求的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
初学者 android 问题。好的,我已经成功写入文件。例如。 //获取文件名 String filename = getResources().getString(R.string.filename
我已经将相同的图像保存到/data/data/mypackage/img/中,现在我想显示这个全屏,我曾尝试使用 ACTION_VIEW 来显示 android 标准程序,但它不是从/data/dat
我正在使用Xcode 9,Swift 4。 我正在尝试使用以下代码从URL在ImageView中显示图像: func getImageFromUrl(sourceUrl: String) -> UII
我的 Ubuntu 安装 genymotion 有问题。主要是我无法调试我的数据库,因为通过 eclipse 中的 DBMS 和 shell 中的 adb 我无法查看/data/文件夹的内容。没有显示
我正在尝试用 PHP 发布一些 JSON 数据。但是出了点问题。 这是我的 html -- {% for x in sets %}
我观察到两种方法的结果不同。为什么是这样?我知道 lm 上发生了什么,但无法弄清楚 tslm 上发生了什么。 > library(forecast) > set.seed(2) > tts lm(t
我不确定为什么会这样!我有一个由 spring data elasticsearch 和 spring data jpa 使用的类,但是当我尝试运行我的应用程序时出现错误。 Error creatin
在 this vega 图表,如果我下载并转换 flare-dependencies.json使用以下 jq 到 csv命令, jq -r '(map(keys) | add | unique) as
我正在提交一个项目,我必须在其中创建一个带有表的 mysql 数据库。一切都在我这边进行,所以我只想检查如何将我所有的压缩文件发送给使用不同计算机的人。基本上,我如何为另一台计算机创建我的数据库文件,
我有一个应用程序可以将文本文件写入内部存储。我想仔细看看我的电脑。 我运行了 Toast.makeText 来显示路径,它说:/数据/数据/我的包 但是当我转到 Android Studio 的 An
我喜欢使用 Genymotion 模拟器以如此出色的速度加载 Android。它有非常好的速度,但仍然有一些不稳定的性能。 如何从 Eclipse 中的文件资源管理器访问 Genymotion 模拟器
我需要更改 Silverlight 中文本框的格式。数据通过 MVVM 绑定(bind)。 例如,有一个 int 属性,我将 1 添加到 setter 中的值并调用 OnPropertyChanged
我想向 Youtube Data API 提出请求,但我不需要访问任何用户信息。我只想浏览公共(public)视频并根据搜索词显示视频。 我可以在未经授权的情况下这样做吗? 最佳答案 YouTube
我已经设置了一个 Twilio 应用程序,我想向人们发送更新,但我不想回复单个文本。我只是想让他们在有问题时打电话。我一切正常,但我想在发送文本时显示传入文本,以确保我不会错过任何问题。我正在使用 p
我有一个带有表单的网站(目前它是纯 HTML,但我们正在切换到 JQuery)。流程是这样的: 接受用户的输入 --- 5 个整数 通过 REST 调用网络服务 在服务器端运行一些计算...并生成一个
假设我们有一个名为 configuration.js 的文件,当我们查看内部时,我们会看到: 'use strict'; var profile = { "project": "%Projec
这部分是对 Previous Question 的扩展我的: 我现在可以从我的 CI Controller 成功返回 JSON 数据,它返回: {"results":[{"id":"1","Sourc
有什么有效的方法可以删除 ios 中 CBL 的所有文档存储?我对此有疑问,或者,如果有人知道如何从本质上使该应用程序像刚刚安装一样,那也会非常有帮助。我们正在努力确保我们的注销实际上将应用程序设置为
我有一个 Rails 应用程序,它与其他 Rails 应用程序通信以进行数据插入。我使用 jQuery $.post 方法进行数据插入。对于插入,我的其他 Rails 应用程序显示 200 OK。但在
我正在为服务于发布请求的 API 调用运行单元测试。我正在传递请求正文,并且必须将响应作为帐户数据返回。但我只收到断言错误 注意:数据是从 Azure 中获取的 spec.js const accou
我是一名优秀的程序员,十分优秀!