2010-07-15 4 views
2

j'ai une page qui sélectionne tous les éléments sous une forme et les sérialise comme ceci:éléments filtrant d'un sélecteur jQuery

var filter = 'form :not([name^=ww],[id$=IDF] *,.tools *)'; 
var serialized = $(filter).serialize(); 

Cela fonctionne, à moins que le formulaire est autour 600+ éléments. Ensuite, l'utilisateur reçoit une erreur javascript disant que le script est lent et peut rendre leurs navigateurs ne répond pas. Il leur donne ensuite la possibilité d'arrêter l'exécution du script.

J'ai essayé d'exécuter les filtres séparément, j'ai essayé d'utiliser .not sur les sélecteurs, puis les sérialiser, mais je rencontre l'un des deux problèmes. Soit il s'exécute plus vite sans l'erreur, mais aussi ne filtre pas les éléments, ou il filtre les éléments et me donne l'erreur de script lente.

Des idées?

+2

* pourquoi, oh pourquoi * auriez-vous plus de 600 éléments d'entrée sous une forme en html!?!? –

+0

votre problème n'est pas le sélecteur. repensez votre page afin qu'elle utilise moins de champs de saisie. redessinez votre logique afin qu'elle n'ait pas besoin de sérialiser des centaines d'éléments dans un script. –

+0

ayant moins de champs d'entrée n'est pas une option. Je ne peux pas entrer dans trop de détails, mais c'est par conception –

Répondre

5

Avec plus de 600 éléments cela va être mort lente. Vous devez offrir à Sizzle (le moteur de sélection de jQuery) des opportunités d'optimisation.

Considérons d'abord le fait que jQuery peut utiliser la méthode querySelectorAll nativement pris en charge (dans les navigateurs modernes) si votre sélecteur est conforme à la CSS3 spec (ou au moins dans la mesure de ce qui est actuellement pris en charge dans les navigateurs).

Avec votre cas, cela signifierait passer un seul sélecteur simple à :not au lieu de 3 (1 simple, 2 complexe).

form :not([name^=ww]) 

Ce serait assez rapide ... même si vous ne pas être bon pour les navigateurs qui ne prennent pas en charge querySelectorAll.

Examinez votre sélecteur et réfléchissez à tout ce que Sizzle a à faire avec chaque élément. D'abord, il doit obtenir TOUS les éléments de la page (vous n'êtes pas pré-qualificatif le sélecteur :not avec un tag/class/id). Ensuite, sur chaque élément, il effectue les opérations suivantes:

(en supposant que sa sortie si le résultat d'un chèque est faux)

  1. Vérifiez que le parent a un ancêtre avec le nodeName.toLowerCase() de form.
  2. Vérifiez qu'il n'a pas d'attribut name commençant par ww (opération de base indexOf).
  3. Vérifiez qu'il n'a pas d'ancêtre avec un attribut id se terminant par IDF. (opération coûteuse)
  4. Vérifiez qu'il n'a pas d'ancêtre avec un attribut class contenant tools.

Les deux dernières opérations sont lentes.

Il peut être préférable de construire manuellement une fonction filter, comme ceci:

var jq = $([1]); 
$('form :input').filter(function(){ 

    // Re-order conditions so that 
    // most likely to fail is at the top! 

    jq[0] = this; // faster than constructing a new jQ obj 

    return (

     !jq.closest('[id$=IDF]')[0] 
      // this can be improved. Maybe pre-qualify 
      // attribute selector with a tag name 

     && !jq.closest('.tools')[0] 

     && this.name.indexOf('ww') !== 0 

    ); 

}); 

Remarque: cette fonction est non vérifiée. J'espère que vous avez l'idée ...

+1

+1 Belle analyse. –

+0

Wow, ça a l'air génial! Je vais essayer et afficher les résultats ici. Merci. –

+0

Je pourrais ajouter que je pourrais aider à optimiser cela plus si je pouvais voir le balisage. J'ai encore des questions à ce sujet ... comme: combien y a-t-il d'éléments [id $ = IDF] ', et sont-ils tous différents? Est-il impossible de leur donner le même cours? – James

1

Pourriez-vous juste sérialiser tout le formulaire et faire votre filtrage sur le backend? En outre, pourquoi-oh-pourquoi la forme se développe-t-elle à plus de 600 champs?

+0

Cela fonctionnerait, mais je dois faire une certaine logique sur la forme sérialisée avant de faire une publication –

+0

Eh bien, je vais essayer de renvoyer toutes les données dont vous avez besoin cette logique de retour avec la demande et encore une fois laisser le backend le faire. De cette façon, vous faites simplement 'serialize' sur tout le formulaire qui devrait être assez rapide (par exemple, pas sur une liste, mais sur un seul élément de formulaire) et ensuite montrer un spinner alors que le backend s'éloigne. – rfunduk

0

utiliser le sélecteur :input seulement sélectionner des éléments applicables ..

+0

Je vais essayer –

+0

@barlow, je pense que ma réponse pourrait être fausse .. je crois que serialize ne sélectionne que les éléments ': input' par défaut ... mais jquery api site est en panne pour le moment et ne peut pas vérifier .. –