2017-09-16 46 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