javascript - 防止并发ajax请求,让他们等待
问题描述
我的客户端 Javascript 应用程序需要来自服务器端的特定数据结构(“列表”)。应用程序中的几个不同位置需要访问列表。启动时,这些地方都会发出请求,这会导致对服务器的多个并发请求,以获得相同的数据结构。
我只想向服务器发出一个请求,并让所有请求者简单地得到一个在请求返回时解决的承诺。
我认为方法是创建一个数组或一组承诺。如果第一个请求正在进行中,则每个后续请求都会创建一个 Promise 并将其添加到堆栈中。当响应返回时,系统将遍历堆栈并使用结果解析所有承诺。
问题是我无法找出正确的语法来让它工作。这是我到目前为止所拥有的:
let lists = [];
let loading = false;
let promises = [];
function getLists() {
if (lists.length > 0) {
// return cached copy
return Promise.resolve(lists);
}
/*
This method can get called several times in quick succession on startup.
To prevent sending multiple requests to the server, we maintain
a stack of promises. If there is already a request in-flight, then just
add a promise to the stack and return it. Then resolve all promises
in the stack when the request returns.
*/
let prom = new Promise(); // BAD, NOT ALLOWED
promises.push(prom);
if (!loading) {
callListsApi(); // async call, resolves promises
}
return prom;
}
function callListsApi() {
loading = true;
axios.get("/lists").then(
response => {
loading = false;
if (!response.data || response.data.length == 0) {
lists = [];
} else {
lists = response.data;
}
for (let i = 0; i < promises.length; i++) {
promises[i].resolve(lists); // give all the callers their lists
}
promises = [];
},
error => {
loading = false;
util.handleAxiosError(error);
let msg = util.getAxiosErrorText(error);
for (let i = 0; i < promises.length; i++) {
promises[i].reject(msg);
}
promises = [];
}
);
}
这是行不通的,因为你不能创建一个裸 Promise() 而不在其中放置某种 executor 函数。
我怎样才能重写它以使其工作?
解决方案
弄清楚了。答案不是创建一堆承诺。只是一遍又一遍地向每个请求者返回相同的承诺。我们维护一个主要的承诺,它仅在请求进行中时才存在。这要简单得多。
let lists = [];
let listPromise = null;
function getLists() {
if (lists.length > 0) {
// return cached copy
return Promise.resolve(lists);
}
if (listPromise != null) {
// if we get here, then there is already a request in-flight
return listPromise;
}
listPromise = callListsApi();
return listPromise;
}
function callListsApi() {
return axios.get("/lists").then(
response => {
if (!response.data || response.data.length == 0) {
lists = [];
} else {
lists = response.data;
}
listPromise = null;
return lists;
},
error => {
util.handleAxiosError(error);
listPromise = null;
return util.getAxiosErrorText(error);
}
);
}
推荐阅读
- c# - 将 .csv 数据从流写入 IList
- elasticsearch - 在重新索引弹性搜索时创建用户定义的 ID 和新数据
- cygwin - 每次打开新终端时如何停止回声
- java - 如何将 Java 对象列表检索到 jsp 文件中
- apex-code - 在顶级课程中,如何根据登录的用户将时区设置为动态?
- python - 在 Python 中使用 IF 条件从 SQL 表中导入数据(或仅在 Python 中满足条件时才从 SQL 表中导入数据)
- scheme - Scheme R7RS 在宏展开时设置和使用状态的便携方式?
- yaml - AWS Code Pipeline 根无权执行:iam:PassRole
- python - 使用 python 在 Linux/Ubuntu 中获取给定进程的窗口句柄
- flutter - 在时间轴小部件中添加一个过滤器按钮