2011-01-26 5 views
0

J'ai du JavaScript que j'ai écrit à la rigueur, mais je pense qu'il pourrait être optimisé par quelqu'un de plus intelligent que moi. Ce code fonctionne sur des objets relativement petits, mais il court une bonne quantité de temps, il est donc utile de faire droit:Itérer les objets JavaScript imbriqués - Sale?

/** 
* Determine the maximum quantity we can show (ever) for these size/color combos 
* 
* @return int=settings.limitedStockThreshold 
*/ 
function getMaxDefaultQuantity() { 
    var max_default_quantity = 1; 

    if (inventory && inventory.sizes) { 
     sizecolor_combo_loop: 
     for (var key in inventory.sizes) { 
      if (inventory.sizes[key].combos) { 
       for (var key2 in inventory.sizes[key].combos) { 
        var sizecolor_combo = inventory.sizes[key].combos[key2]; 
        if (isBackorderable(sizecolor_combo)) { 
        //if even one is backorderable, we can break out 
         max_default_quantity = settings.limitedStockThreshold; 
         break sizecolor_combo_loop; 
        } else { 
        //not backorderable, get largest quantity (sizecolor_combo or max_default_quantity) 
         var qoh = parseInt(sizecolor_combo.quantityOnHand || 1); 
         if (qoh > max_default_quantity) { 
          max_default_quantity = qoh; 
         }; 
        }; 
       }; 
      }; 
     }; 
    }; 

    return Math.min(max_default_quantity, settings.limitedStockThreshold); 
}; 

inventaire En premier lieu, est un objet retourné par JSON. Il a une propriété inventory.sizes qui contiennent toutes les tailles disponibles pour un produit. Chaque taille a une propriété inventory.sizes.combos qui correspond à toutes les couleurs disponibles pour une taille. Chaque combo a également une propriété quantityOnHand qui indique la quantité disponible pour ce combo spécifique. (la structure JSON retournée ne peut pas être modifiée)

Ce que fait le code est de faire défiler chaque taille, puis les combos de chaque taille. Il vérifie ensuite si le combo taille-couleur est rechargeable (via une autre méthode). Si n'importe quel combo est backorderable, nous pouvons arrêter parce que la quantité par défaut est définie ailleurs. Si le combo n'est pas en stock, la valeur de max_default_quantity est la plus grande quantityOnHand que nous trouvons (avec un maximum de settings.limitedStockThreshold). Je n'aime vraiment pas les boucles imbriquées et ma gestion des valeurs mathématiques et par défaut me semble trop compliquée.

En outre, cette fonction entière est enveloppée dans un objet jQuery beaucoup plus grand si cela aide à le nettoyer.

+2

FYI, vous n'avez pas besoin de points-virgules à la fin des blocs de code JavaScript. – Jacob

+0

@Jacob J'oserais dire! Si j'écrivais cela, il n'y aurait pas un seul point-virgule * encombrant le code! –

+0

J'ajoute des points-virgules car le code semble mieux compresser en utilisant JS-Minifier. C'est une habitude récente que j'ai ramassée. – Brandon0

Répondre

0

Malheureusement, JavaScript n'a pas beaucoup de possibilités de traitement de collection élégant si vous devez supporter des navigateurs plus anciens, donc sans l'aide de bibliothèques supplémentaires, une boucle imbriquée comme celle que vous avez écrite est la façon de aller. Vous pourriez envisager d'avoir les valeurs précalculées côté serveur, éventuellement mises en cache, et de les inclure dans le JSON pour éviter d'avoir à exécuter les mêmes calculs encore et encore.

+0

[JavaScript fonctionnel] (http://osteele.com/sources/javascript/functional/) :-) –

+0

@Jacob, jamais entendu parler des méthodes d'itération Array les plus récentes (map, reduce, filter, each ...)? https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array#Iteration_methods Bien sûr, IE 8 ne les supporte peut-être pas, mais il est faux de dire que JS n'a pas grand-chose à faire. capacités de traitement de la collection ellegant –

+0

Réponse éditée pour spécifier qu'elle ne s'applique qu'aux anciens navigateurs. – Jacob

0

Avez-vous envisagé d'utiliser map-reduce? Voir un live exemple d'une approche fonctionnelle.

Cet exemple particulier utilise underscore.js afin que nous puissions le garder à un niveau élégant sans avoir à implémenter les détails.

function doStuff(inventory) { 
    var max = settings.limitedStockThreshold; 
    if (!(inventory && inventory.sizes)) return; 

    var quantity = _(inventory.sizes).chain() 
     .filter(function(value) { 
      return value.combos; 
     }) 
     .map(function(value) { 
      return _(value.combos).chain() 
       .map(function(value) { 
        return isBackorderable(value) ? max : value.quantityOnHand; 
       }) 
       .max().value(); 
     }) 
     .max().value(); 

    return Math.min(quantity, max); 
} 

En ce qui concerne une explication:

Nous prenons les inventory.sizes et en retirer tout qui ne contiennent pas des combos. Nous cartographions ensuite chaque taille à la quantité maximale de sa couleur. Nous faisons cette cartographie chaque combo soit à sa quantité ou la quantité maximale si backordable. Nous prenons alors un maximum de cet ensemble.

Enfin, nous prenons un maximum de maxQuantities par taille.

Nous faisons toujours un double pour la boucle puisque nous prenons deux .max sur l'ensemble mais il ne semble pas aussi sale.

Il existe également quelques vérifications d'if que vous aviez en place et qui sont toujours présentes.

[Modifier]

Je suis assez sûr que le code ci-dessus peut être optimisé beaucoup plus. mais c'est une façon différente de voir les choses.

+0

Ce code est certainement élégant. Existe-t-il un moyen de refactoriser ceci sans compter sur la bibliothèque de soulignement? Peut-être simplement en utilisant jQuery.map() à la place? J'essaie d'éviter d'ajouter une bibliothèque supplémentaire pour une seule tâche. – Brandon0

+0

Vous pouvez définir vous-même toutes ces fonctions. La carte, le filtre et le max ne sont pas si difficiles à définir. Regardez la source de soulignement. Je ne l'ai utilisé que parce que les détails gênants du navigateur sont cachés. Si vous êtes limité à un navigateur décent alors 'array.reduce',' array.map', 'array.filter' sont tous natifs. Si vous allez écrire du code fonctionnel, faites-le tout au long du projet, pas seulement une fonction. Le underscore est une ceinture utilitaire légère qui facilite le travail. – Raynos