2012-11-06 32 views
1

我需要在JavaScript/jQuery中執行幾個函數,但我想避免阻塞UI。沒有UI塊的函數處理鏈

由於應用程序的性質,AJAX不是一個可行的解決方案,因爲這些功能很容易達到數千個。這樣做異步會殺死瀏覽器。

所以,我需要一些鏈接瀏覽器需要處理的函數的方法,並且只有在第一個完成後才發送下一個函數。

的算法是這樣的

對於步驟2至15

HTTP:得到物品的量當前步驟(從幾百到數千個地方範圍)

對於每一個項目,HTTP:得到的結果

正如你看到的,我有兩個GET-請求 - 「鏈」不知何故,我需要管理......尤其是最內層的環附近崩潰的瀏覽器立即,如果它asynchroniously做 - 但我還是想用戶能夠操作頁面,所以純粹的(阻塞)同步方式將不起作用。

回答

4

您可以輕鬆地異步執行此操作,而無需立即啓動所有請求。你所需要做的就是管理一個隊列。以下是爲了清晰起見的僞代碼。它很容易轉換成真正的AJAX請求:

// Basic structure of the request queue. It's a list of objects 
// that defines ajax requests: 
var request_queue = [{ 
    url : "some/path", 
    callback : function_to_process_the_data 
}]; 

// This function implements the main loop. 
// It looks recursive but is not because each function 
// call happens in an event handler: 
function process_request_queue() { 
    // If we have anything in the queue, do an ajax call. 
    // Otherwise do nothing and let the loop end. 
    if (request_queue.length) { 
     // Get one request from the queue. We can either 
     // shift or pop depending on weather you prefer 
     // depth first or breadth first processing: 
     var req = request_queue.pop(); 
     ajax(req.url,function(result){ 
      req.callback(result); 
      // At the end of the ajax request process 
      // the queue again: 
      process_request_queue(); 
     } 
    } 
} 

// Now get the ball rolling: 
process_request_queue(); 

所以基本上我們把ajax調用本身變成一個僞循環。它基本上是遞歸編程的經典延續傳遞風格。

在你的情況下,請求的例子是:

request_queue.push({ 
    url : "path/to/OUTER/request", 
    callback : function (result) { 
     // You mentioned that the result of the OUTER request 
     // should trigger another round of INNER requests. 
     // To do this simply add the INNER requests to the queue: 

     request_queue.push({ 
      url : result.inner_url, 
      callback : function_to_handle_inner_request 
     }); 
    } 
}); 

這是相當靈活的,因爲你不僅有處理請求或者廣度的選擇第一或深度第一(移比POP)。但是你也可以使用splice來將東西添加到隊列的中間,或者使用unshift vs push來將請求放在隊列的頭部以獲得高優先級的請求。

您還可以通過在每個循環中彈出多個請求來增加同時發生的請求數。只是一定要每次只叫循環只process_request_queue一次,以避免同時請求的指數增長:

// Handling two simultaneous request channels: 
function process_request_queue() { 
    if (request_queue.length) { 
     var req = request_queue.pop(); 
     ajax(req.url,function(result){ 
      req.callback(result); 
      // Best to loop on the first request. 
      // The second request below may never fire 
      // if the queue runs out of requests. 
      process_request_queue(); 
     } 
    } 
    if (request_queue.length) { 
     var req = request_queue.pop(); 
     ajax(req.url,function(result){ 
      req.callback(result); 
      // DON'T CALL process_request_queue here 
      // We only want to call it once per "loop" 
      // otherwise the "loop" would grow into a "tree" 
     } 
    } 
} 
+0

這真是太棒了! –

1

你可以使這個ASYNC和使用我前段時間寫的small library,這將讓你排隊函數調用。

+0

似乎是個不錯的庫,但它只有一個隊列......對於我的算法,我想我需要一個隊列對於每一個二級迭代? –

+1

@FlorianPeschka:你只需要一個隊列。看到我的答案如何做到這一點。 – slebetman