2017-09-16 50 views
2

在我的应用程序的反应,我有一个网格。用户可以一次选择多个网格行,然后单击一个按钮对所选网格行执行批量操作。作出反应 - 控制多个Ajax调用

在服务器端我有一个脚本,我想为每个选定的行执行(使问题变得简单,我在下面的示例中针对每个选定行调用“jsonplaceholder.typicode.com”)的批量操作按钮。点击批量操作按钮后,我会在操作创建器中获取selectedRows,在迭代选定行的同时为每个选定行创建ajax调用。

由于selectedRows可能包含超过1000个项目,如果我只是反复让使用foreach循环Ajax调用,浏览器页面最终可能会停止响应每个请求都解决了。因此,我使用下面的解决方案,以5批为单位发送请求,然后等到这5个问题解决。上述

// 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. 从网格中选择超过5行,然后点击批量操作按钮,
  2. 再次选择超过5行,并点击批量操作按钮,
  3. 现在我看到同时启动10个请求。

我怎么能限制呢?

跟进质询,这里提到的被要求在React - controlling async calls smartly without any side effect in complex applications

这个问题的JavaScript, React - sending multiple simultaneous ajax calls

回答

2

async模块具有此功能:async.queue。首先你定义一个任务函数。然后你给它一个任务 - 在你的情况下,一排行和你想要采取的行动。如果已经有任务正在进行,任务将被运行或添加到队列中。任务完成后,下一个将从队列中取出。

更好的是,您可以只为一行定义任务函数,并将队列的并发性设置为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); 
    } 
} 
+0

感谢您的回答,让我试试这个。 –

1

跟进问题这必将在你的代码,因为发生了问题,没有检查,看是否已经有批量请求正在运行或没有运行。您将不得不在代码中进行一些更改以正确适应批处理调用。

第1步:

首先,保持标志在你的状态,看是否已经批量请求正在运行,说flagBatchRunning。在触发请求之前,在您的makeBatchCalls函数中将其设置为true。

现在一旦Promise.all得到解决,所有的请求都完成后,再次使其为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); 
    } 
} 

PS。这只是一个伪代码。不要将逻辑放在行为创建者身上。它应该由reducer(改变状态)和saga/thunk来处理异步操作。

希望这会有所帮助。

+0

1.谁会调用这个回调? –

+0

我无法区分每个按钮单击的响应。 –

+1

1.一旦解决了所有的承诺,就应该调用该回调。检查下一组更新。更新我的答案以显示如何调用回调。 – codeslayer1