2011-12-08 5 views
0

J'ai essayé de mettre cela en termes génériques pour le rendre plus facile à comprendre. S'il vous plaît, comprenez que c'est le concept, pas l'exemple spécifique que j'essaie de surmonter. OK, donc j'ai un peu de JavaScript qui appelle un serveur pour obtenir un objet, disons un ordre. L'ordre a des propriétés comprenant un tableau d'ID d'article de commande. Je veux ensuite faire une boucle à travers lesdits ID et obtenir les enregistrements d'éléments de commande et les retourner dans un tableau, comme ceci:Rappels JQuery/JavaScript, boîte de dialogue modale

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; 
} 

La question est qu'il pourrait y avoir un bon nombre de points de commande, mais je dois les obtenir à partir du serveur 1 à la fois (ne demandez pas, cela ne changera pas). Donc, je veux leur faire savoir (à l'aide d'une boîte de dialogue modale de l'interface utilisateur jQuery) combien d'ordres il y a pour qu'ils aient une idée du temps que cela prendra. Alors, je tente d'injecter la ligne indiquée ci-dessous:

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; 
} 

Le problème est que montre la fenêtre, mais seulement quand tout est complet. J'ai appris d'une question précédente que vous pouviez utiliser setTimeout pour afficher le modal, mais comment retourner le tableau que je construis?

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); 
} 

Je l'ai fait aussi une deuxième fonction setTimeout pour montrer les progrès, mais il va droit au dernier et aucune des fonctions courir, comme ceci:

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); 
} 

Merci à l'avance!

+0

Vous nous dites d'ignorer la mise en œuvre de '' GetOrderItemIDs' et GetOrderItem', mais vous les traitez comme des fonctions synchrones tout en déclarant que vous obtenez des données du serveur. Cela semble être la racine des problèmes que vous rencontrez. – nrabinowitz

Répondre

1

Vous devrez le faire de manière asynchrone. Il n'y a pas d'autre moyen d'actualiser l'interface utilisateur. See this related question. Cela signifie que votre code d'appel devra passer de:

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

Pour:

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

On peut supposer que vous avez seulement été en mesure de sortir avec ce code synchrone en faisant vos demandes de serveur synchrone, ainsi attacher le navigateur, etc. Si vous allez vous lancer dans l'asynchronisme, vous pouvez aussi profiter de tous les avantages potentiels. Par exemple, votre modal pourrait être mis à jour pour indiquer le nombre de commandes restent à télécharger:

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); 
      } 
     }); 
    }); 
} 

Edit: Pour limiter les demandes simultanées, ne pas utiliser $.each(). Au lieu de cela commencer seulement le nombre de requêtes simultanées que vous voulez, puis lancer le reste des demandes dans le gestionnaire de succès de la demande:

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

Cela semble très intéressant, mais comment puis-je limiter le nombre de demandes simultanées au serveur? –

+0

@JohnWilliams - Limite à seulement 1 demande à la fois, ou à une limite arbitraire? – gilly3

+0

Ce dernier serait le meilleur, mais je vais prendre soit. Merci d'avance! –

0

Si vous affichez la boîte de dialogue avant le serveur individuel voyages, il n'a de sens que vous attendez une action de l'utilisateur (un bouton OK par exemple). En effet, votre code suivant l'appel dialog() continuera à s'exécuter quel que soit l'effet de la boîte de dialogue.

Si vous souhaitez les informer de la progression, vous devez mettre à jour la boîte de dialogue chaque fois qu'une demande de serveur est faite.

Dans ce cas, la fonction GetOrderItem(this) ne peut pas être ignorée. S'il s'agit d'un appel AJAX, le reste de la méthode parente GetOrderItems() continuera à s'exécuter avant la fin des appels AJAX.

Alors vous devez faire quelque chose comme ceci:

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); 
     } 
    }); 
} 
Questions connexes