2011-12-08 86 views
0

我試圖把它放在通用的術語中,以便更容易理解。請理解這是一個概念,而不是我想要克服的具體例子。JQuery/JavaScript回調,模態對話框

OK,所以我有一些JavaScript,使一個服務器調用來獲取一個對象,讓我們說一個訂單。該訂單具有包含訂單商品ID數組的屬性。那麼我想遍歷該ID和得到訂單項記錄,並以一個數組的形式返回他們,就像這樣:

function GetOrderItems(orderId){ 
    var orderItemIDs = GetOrderItemIDs(orderId); // array of order item IDs 
    var orderItems = []; 
    $.each(orderItemIDs, function(){ 
     var orderItem = GetOrderItem(this); // ignore this function's implementation 
     orderItems.push(orderItem); 
    }); 
    return orderItems; 
} 

的問題是,可能有相當多的訂單項目,但我必須讓他們從服務器1一次(不要問,這不會改變)。所以,我想讓他們知道(使用jQuery UI模式對話框)有多少訂單,以便他們知道需要多長時間。所以,我試圖注入下面提到的線:

function GetOrderItems(orderId){ 
    var orderItemIDs = GetOrderItemIDs(orderId); // array of order item IDs 
    var orderItems = []; 
    $("#modalDiv").dialog({title: orderItemIDs.length + " order items to get."}); 
    $.each(orderItemIDs, function(){ 
     var orderItem = GetOrderItem(this); // ignore this function's implementation 
     orderItems.push(orderItem); 
    }); 
    return orderItems; 
} 

問題是,對話框顯示,但只有當一切都完成。我從前面的問題中學習到,你可以使用setTimeout來獲取模態,但是如何返回我正在構建的數組?

function GetOrderItems(orderId){ 
    var orderItemIDs = GetOrderItemIDs(orderId); // array of order item IDs 
    var orderItems = []; 
    $("#modalDiv").dialog({title: orderItemIDs.length + " order items to get."}); 
    setTimeout(function(){ 
     $.each(orderItemIDs, function(){ 
      var orderItem = GetOrderItem(this); //ignore this function's implementation 
      orderItems.push(orderItem); 
     }); 
     return orderItems; 
    },0); 
} 

我也做了第二setTimeout函數出現進展,但它直接到最後一個,沒有的功能的運行,像這樣:

function GetOrderItems(orderId){ 
    var orderItemIDs = GetOrderItemIDs(orderId); // array of order item IDs 
    var orderItems = []; 
    $("#modalDiv").dialog({title: orderItemIDs.length + " order items to get."}); 
    setTimeout(function(){ 
     $.each(orderItemIDs, function(){ 
      setTimeout(function(){ 
       var orderItem = GetOrderItem(this); //ignore this function's implementation 
       orderItems.push(orderItem); 
      },500); 
     }); 
     return orderItems; 
    },0); 
} 

提前感謝!

+0

你告訴我們忽視GetOrderItemIDs'和'GetOrderItem'的'執行,但你把它們當作同步功能,同時指出,你從服務器獲取數據。這似乎可能是你遇到的問題的根源。 – nrabinowitz

回答

1

你必須以異步方式做到這一點。沒有其他方式可以讓用戶界面刷新。 See this related question。這意味着您的調用代碼將不得不改變來自:

var orderItems = GetOrderItems(orderId); 
// do something with orderItems 

要:

GetOrderItems(orderId, function (orderItems) { 
    // do something with orderItems 
}) 

想必,你只能夠通過使您的服務器請求同步與此同步代碼脫身,從而捆綁瀏覽器等等。如果你要着手進入異步速度,你還可以利用所有潛在的好處。例如,你的模式可以被更新,以表明多少訂單仍有待下載:

function GetOrderItems(orderId, callback){ 
    var orderItemIDs = GetOrderItemIDs(orderId); // array of order item IDs 
    var orderItems = []; 
    var orderItemCount = orderItemIDs.length; 
    $("#modalDiv").dialog({title: "<span id=\"orderItemRemaining\">" + orderItemCount + "</span> order items to get."}); 
    $.each(orderItemIDs, function(){ 
     $.get("/getOrderItem?orderId=" + this, function (orderItem) { 
      orderItems.push(orderItem); 
      var remaining = orderItemCount - orderItems.length; 
      $("#orderItemRemaining").text(remaining); 
      if (!remaining) { 
       callback(orderItems); 
      } 
     }); 
    }); 
} 

編輯:要限制併發請求,請不要使用$.each()。相反,啓動要併發請求的只是號碼,然後發起請求的成功處理請求的其餘部分:

function GetOrderItems(orderId, callback){ 
    var orderItemIDs = GetOrderItemIDs(orderId); // array of order item IDs 
    var orderItems = []; 
    var orderItemCount = orderItemIDs.length; 
    $("#modalDiv").dialog({title: "<span id=\"orderItemRemaining\">" + orderItemCount + "</span> order items to get."}); 
    var maxConcurrent = 3; 
    for (var i = 0; i < maxConcurrent; i++) { 
     getOrderItem(orderItemIDs.shift()); 
    } 
    function getOrderItem(orderItemID) { 
     $.get("/getOrderItem?orderId=" + orderItemID, function (orderItem) { 
      orderItems.push(orderItem); 
      var remaining = orderItemCount - orderItems.length; 
      $("#orderItemRemaining").text(remaining); 
      if (remaining) { 
       getOrderItem(orderItemsIDs.shift()); 
      } 
      else 
       callback(orderItems); 
      } 
     }); 
    } 
} 
+0

這看起來很有趣,但我怎樣才能限制併發請求的數量到服務器? –

+0

@JohnWilliams - 一次僅限一次請求,或限制一些任意限制? – gilly3

+0

後者將是最好的,但我會採取。提前致謝! –

0

如果你是顯示之前的單個服務器的對話框車次這沒有任何意義,除非您正在等待用戶的操作(例如,一個OK按鈕)。這是因爲在調用dialog()之後,您的代碼將繼續執行,而不管對話的效果如何。

如果您想通知他們進度,每次發出服務器請求時都必須更新對話框。

在這種情況下,函數GetOrderItem(this)不能被忽略。如果是AJAX調用,則其父方法GetOrderItems()的其餘部分將在AJAX調用完成之前繼續執行。

所以,你會做這樣的事情:

var someGlobalCounter = 0; 

function GetOrderItem(item) { // gets called X number of times 
    $.ajax({ 
     ... 
     success: function(retrievedItem) { 
      someGlobalCounter++; 
      $('#modalDiv').html(someGlobalCounter + ' records retrieved so far...'); 
      orderItems.push(retrievedItem); 
     } 
    }); 
}