2011-08-08 33 views
13

我想知道如何在n組中做ajax調用。如何在jQuery中批量處理ajax請求?

這裏是我的使用案例:

我有一個表顯示使用情況數據。您可以鑽取每一行,並且如果每行都有一個可以深入鑽取的公共屬性,則可以選擇一次鑽取所有這些屬性。對於每一行,都會調用ajax來獲取要附加到表中的數據。

在某些情況下,最多可同時鑽取50行。正如你可以想象的那樣,這給服務器帶來了很大的壓力。如何以最佳方式將這些電話以較小的批次發送,然後再等待批量發出?

我知道有像jquery消息隊列這樣的插件能夠幫助我,但這是一個工作項目,所以我們希望儘可能地避免插件。

+1

因此使自己的隊列管理器:) –

+0

這個答案通常有助於http://stackoverflow.com/questions/42425885/trying-to-make-2-ajax -calls-via-jquery-and-then-prepending-the-data-taken-from/42426722#42426722 –

回答

16

你可以看看使用jQuery.when,它允許您在所有請求完成時執行回調函數。

$.when($.ajax("request1"), $.ajax("request2"), $.ajax("request3")) 
.done(function(data1, data2, data3){ 
     // Do something with the data 
}); 

或者

$.when($.ajax("request1"), $.ajax("request2"), $.ajax("request3")) 
.then(successCallback, errorHandler); 

有關更多信息,請參閱以下post

此外,我不確定您對使用插件的理解應該受到您處於工作環境中的事實的影響,尤其是如果它簡化了您的工作。因此可以提高生產力。當然,你必須仔細選擇你的插件,因爲質量和長期維護可能是一個問題。

+1

jQuery [Deferred object](http://api.jquery.com/category/deferred-object/)絕對是處理異步請求的方式。使用$ .when和$ .done處理$ .ajax承諾對象和由setTimeout產生的代碼時,我的代碼變得更清晰並且更具可讀性。好決定。 – stinkycheeseman

+0

是理解$ .when(),但它看起來很煩瑣用於我的情況,即5K xhr2查詢,發送批次爲50(Chrom引發SPDY服務器的內存錯誤),Chromium人最終會修復,但我需要調節現在。我想我可以嘗試下面的遞歸建議。這聽起來是對的嗎? –

7

使用jQuery進行Ajax調用通常是異步的。因此,如果您有50行,jQuery將異步發送所有50個請求 - 當您從服務器獲得響應時,您無法控制處理的順序。

您可以在$.ajax呼叫使用async: false這樣,只有一個請求是通過你的行發送到服務器,你的循環:

$.ajax({ 
    url: location, 
    data: params, 
    async: false, 
    success: function(msg) { // do something} 
}); 

這種方法(async: false)的問題是,用戶可能會遇到「凍結」或無響應的頁面。

另一種方法是使用遞歸在JavaScript,以便調用仍然異步但Ajax調用仍然等待每行類似如下的成功事件:

var maxRows = 50; 

function myFunc(index) { 
    $.ajax({ 
     url: location, 
     data: params, 
     async: true, 
     success: function(msg) { 
      if (index < maxRows) { 
       // do something 
      } 
      else { 
       return; //index equals maxRows--stop the recursion 
      } 
      index++; 
      myFunc(index); //call the function again 
     } 
    }); 

    $(document).ready(function() { 
     myFunc(0);  
    }); 
} 
+0

我需要做5K的xhr2查詢,將它批量發送給50個(Chrome會引發SPDY服務器的內存錯誤),鉻人將最終修復,但我現在需要節流。我認爲你的遞歸方法有前途。 –

3

我同意eicto:如果您不能整合另一個,請自己創建消息管理器。這是我的一個小小的破解:

var AjaxQueue = function(max) { 
    this.max = max; 
    this.requests = []; 
    this.current = 0; 
} 

AjaxQueue.prototype.ajax = function(opts) { 
    var queue = this; 
    opts.complete = function(jqXHR, textStatus) { 
    queue.current -= 1; 
    queue.send(); 
    }; 
    this.requests.push(opts); 
    this.send(); 
} 

AjaxQueue.prototype.send = function(opts) { 
    while (this.current < this.max && this.requests.length > 0) { 
    $.ajax(this.requests.unshift()); 
    this.current += 1; 
    } 
} 

我還沒有嘗試過使用它,所以肯定會有錯誤。另外它假定你沒有使用complete選項。它只是壓倒它。如果你可以檢查它,並確保先前的完整功能仍然被調用。

+0

啊,這很完美。我會玩弄它,看看我能做些什麼。我唯一擔心的是,這種情況是否存在潛在的競爭條件?我知道很少有2個Ajax調用同時完成,所以值得考慮一下嗎? – stinkycheeseman

+2

否瀏覽器確保兩個用戶定義的函數不能同時運行。這就是爲什麼運行無限循環會鎖定與網頁的交互。它也使事情變得更簡單。 –

+0

任何使用示例的機會? – PlanetWilson

0

調用的遞歸批處理適合我。但是,因爲我正在獲取4K的XHR2 blob並將每個節點保存在IndexedDB(PouchDB)中。我有線程爲XHR2和IDB放。所以,我不得不更加複雜一點:

 for (var i in info.LayerInfo) { 
     var imageType = (info.LayerInfo[i].Class == "BASE") ? "jpg" : "png"; 
     info.LayerInfo[i].SaveCount = 0; 
     getLayer(0, info, info.LayerInfo[i], info.LayerInfo[i].Path, imageType); 
    } 
} 

function getLayer(index, info, layer, base, imageType) { 
    if (layer.Files.length == 0) { 
     console.log("Thread done: " + index + " SaveCount: " + layer.SaveCount); 
     return; 
    } 
    var val = layer.Files.shift(); 
    var path = base + "/" + val.id + "." + imageType; 
    $xhr.ajax({ 
     url: path, 
     dataType: "blob", 
     success: function (data) { 
      console.log("fetched: ", layer.Type + "-" + val.id); 
      saveBlob(data, val.size, val.id, layer.Type, index, info, layer, base, imageType); 
      if (index < maxThreads - 1) { 
       getLayer(++index, info, layer, base, imageType); 
      } else { 
       return; 
      } 
     } 
    }); 
} 

function saveBlob(blob, length, id, layerID, index, info, layer, base, imageType) { 
    if (blob.size != length) { 
     console.error("Blob Length found: ", blob.size, " expected: ", length); 
    } 
    var blobID = layerID + "-" + id; 
    var type = blob.type; 
    DB.putAttachment(blobID + "/pic", blob, type, function (err, response) { 
     if (err) { 
      console.error("Could store blob: error: " + err.error + " reason: " + err.reason + " status: " + err.status); 
     } else { 
      console.log("saved: ", response.id + " rev: " + response.rev); 
      layer.SaveCount++; 
      getLayer(index, info, layer, base, imageType); 
     } 
    }); 
}