Javascript React-控制多个Ajax调用
在react应用程序中,我有一个网格。用户可以一次选择多个网格行,然后单击按钮对所选网格行执行批量操作 在服务器端,我有一个脚本,我希望在单击批量操作按钮时为每个选定行执行该脚本(为了简化问题,我在下面的示例中为每个选定行调用“jsonplaceholder.typicode.com”)。单击bulk action按钮,我在action creator中获得selectedRows,在这里我迭代selectedRows并对每个选定行进行ajax调用 由于selectedRows可能包含1000多个项目,并且如果我只是使用forEach循环迭代地进行ajax调用,那么浏览器页面最终可能会在每个请求得到解决之前停止响应。因此,我使用下面的解决方案,以5个为一批发送请求,然后等待这5个请求得到解决Javascript React-控制多个Ajax调用,javascript,ajax,reactjs,promise,axios,Javascript,Ajax,Reactjs,Promise,Axios,在react应用程序中,我有一个网格。用户可以一次选择多个网格行,然后单击按钮对所选网格行执行批量操作 在服务器端,我有一个脚本,我希望在单击批量操作按钮时为每个选定行执行该脚本(为了简化问题,我在下面的示例中为每个选定行调用“jsonplaceholder.typicode.com”)。单击bulk action按钮,我在action creator中获得selectedRows,在这里我迭代selectedRows并对每个选定行进行ajax调用 由于selectedRows可能包含1000多
// Action creator, selectedRows is an array.
function onGridRowsSelection(selectedRows) {
makeBatchCalls(selectedRows,5)
}
async function makeBatchCalls(selectedRows, length) {
let test = arrayIds.reduce((rows, key, index) => (index % length == 0
? rows.push([key])
: rows[rows.length-1].push(key)) && rows, []);
let Batchresults = []; //convert them to two dimensionl arrays of given length [[1,2,3,4,5], [6,7,8,9,10]]
for (calls of test) {
Batchresults.push(await Promise.all(calls.map((call)=>{
fetch(`https://jsonplaceholder.typicode.com/posts/${call}`)
})
));
}
return Promise.all(Batchresults); //wait for all batch calls to finish
}
上面的解决方案很好,但有一个问题
这个问题是的后续问题,这是不可避免的,因为在您的代码中,没有检查批处理请求是否已经在运行。您必须对代码进行一些更改,以正确地适应批处理调用 步骤1: 首先,在您的状态中保留一个标志,以查看是否已经有批处理请求正在运行,比如flagBatchRunning。在触发请求之前,在makeBatchCalls函数中将其设置为true 现在,一旦Promise.all得到解决,并且所有请求都已完成,请再次将其设置为false 在动作创建者中,检查此标志是否为false
function onGridRowsSelection(selectedRows) {
if(!state.flagBatchRunning){
makeBatchCalls(selectedRows,5)
}
}
步骤2:
仅仅保留一个标志对您没有帮助,因为在批处理调用运行时,用户很可能再次单击批量操作按钮,在这种情况下,您的onGridRowsSelection将忽略此更新。因此,现在需要保留某种变量来存储这些挂起的批处理请求
为此,创建一个数组,比如pendingRequestsArray。继续在此阵列中添加所有挂起的更新,一旦上一批完成,从挂起阵列中选取所有请求,并对它们进行批处理调用
所以你的函数现在变为这个
// Action creator, selectedRows is an array.
function onGridRowsSelection(selectedRows) {
if(!state.flagBatchRunning){
makeBatchCalls(selectedRows,5)
}else{
state.pendingRequestsArray.push(selectedRows); //push to pending array
}
}
async function makeBatchCalls(selectedRows, length) {
let test = arrayIds.reduce((rows, key, index) => (index % length == 0
? rows.push([key])
: rows[rows.length-1].push(key)) && rows, []);
let Batchresults = []; //convert them to two dimensionl arrays of given length [[1,2,3,4,5], [6,7,8,9,10]]
for (calls of test) {
Batchresults.push(await Promise.all(calls.map((call)=>{
fetch(`https://jsonplaceholder.typicode.com/posts/${call}`)
})
));
}
return Promise.all(Batchresults)
.then(function(results){
//call callback function here
promiseResolved();
}); //wait for all batch calls to finish
}
//assuming you have a callback function like this once all your batch calls finish
function promiseResolved(){
//set flagRunning to false
state.flagBatchRunning = false;
//if any pending requests are present, process them, else ignore
if(state.pendingRequestsArray.length > 0){
state.flagBatchRunning = true;
makeBatchCalls(pendingRequestsArray, pendingRequestsArray.length);
}
}
这只是一个伪代码。不要把逻辑放在你的行动中。它应该由reducer(改变状态)和saga/thunk负责异步操作
希望这能有所帮助。异步
模块有一个功能:。首先定义一个任务函数。然后给它一个任务——在您的例子中,是一个行数组和您希望它执行的操作。将运行该任务,或将其添加到队列(如果已存在正在进行的任务)。任务完成后,将从队列中获取下一个任务
更好的是,您可以只为一行定义任务函数,并将队列的并发性设置为5。当用户单击该按钮时,您将向队列中添加大量任务,每选定一行一个任务。5个任务将立即开始运行,其余任务将排队。这可能比您正在尝试的要好,因为这样用户可以启动2个任务,然后立即启动另外3个任务,并且它们都将并行运行
请尝试以下代码:
const async = require('async'); // or whatever mechanism you're using for module management.
const queue = async.queue((row, callback) => {
fetch(`https://jsonplaceholder.typicode.com/posts/${call}`)
.then(callback, callback);
}, 5);
function onGridRowsSelection(selectedRows) {
for (let call of selectedRows) {
queue.push(call);
}
}
1.谁将调用此回调?我无法区分每次单击按钮的响应。1。一旦您的所有承诺都得到解决,就应该调用此回调。检查下一组更新。更新了我的答案以显示如何呼叫回拨。谢谢你的答案,让我试试这个。