2011-12-08 54 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); 
     } 
    }); 
}