Als Engelssprekenden zijn onze gedachten gericht op het interpreteren van gegevens en tekst van links naar rechts. Echter, zo blijkt, veel van de moderne JavaScript-selector-engines (jQuery, YUI 3, NWMatcher) en de native querySelectorAll
, ontleed de strings van rechts naar links.
Het is belangrijk om op te merken dat je je vaker wel dan niet zorgen hoeft te maken over de prestaties van de selector - zolang je selectors niet irritant zijn. jQuery's Sizzle is ongelooflijk snel en meegaand.
Overweeg de volgende selector:
$ ('. box p');
Hoewel sommige - over het algemeen oudere - selector engines eerst de DOM zullen ondervragen voor het element met een klasse
van doos
, en ga dan verder met het vinden van een p
tags die kinderen zijn, jQuery werkt in omgekeerde volgorde. Het begint met het doorvragen van de DOM voor allemaal alineatags op de pagina en werkt dan ver omhoog in de bovenliggende knooppunten en zoekt naar .doos
.
We kunnen de uitstekende JsPerf.com-website gebruiken om dit uit te testen.
// De opmaak// De test // 1. $ ('# box p'); // 2. $ ('# box'). Find ('p');Hallo
De afbeelding hierboven laat zien dat gebruik vind()
of kinderen()
is ongeveer 20-30% sneller, afhankelijk van de browser.
De jQuery-bibliotheek heeft een optimalisatie die onmiddellijk zal bepalen of een ID kaart
werd doorgegeven aan het jQuery-object ( $ ( '# Box')
). Als dat het geval is, hoeft Sizzle niet te worden gebruikt; in plaats daarvan wordt de selector snel doorgegeven aan getElementById
. En, natuurlijk, als de browser modern genoeg is, querySelectorAll
zal het overnemen voor Sizzle.
Aan de andere kant, met $ ('# box p')
, jQuery moet deze string ontleden met de Sizzle API, wat iets langer zal duren (hoewel Sizzle wel een optimalisatie heeft voor selectors die beginnen met een ID kaart
). Dit is precies waarom het ook iets sneller is om dingen als te doen $ ('. Elems'). Eerst ()
over- $ ( 'Elems:. First')
. De laatste selector moet worden geparseerd.
Laten we een ander voorbeeld bekijken:
$ ('# container>: uitgeschakeld');
Deze selector lijkt geschikt. Zoek alle uitgeschakelde ingangen (of eigenlijk elementen) die zich binnenin bevinden #houder
. Echter, zoals we hebben geleerd, jQuery en de native querySelectorAll
werk van rechts naar links. Dit betekent dat jQuery letterlijk elk element in de DOM grijpt en bepaalt of het is invalide
attribuut is ingesteld op true. Merk op dat er geen pre-filtering is om eerst alle invoer op de pagina te vinden. In plaats daarvan wordt elk element in de DOM ondervraagd.
// Van de jQuery-bron uitgeschakeld: functie (elem) return elem.disabled === true;
Zodra het een verzameling heeft samengesteld, reist het vervolgens de keten op naar de ouder en bepaalt of het is #houder
. Zeker, dit is niet effectief, en hoewel het klopt dat misschien te veel aandacht in de gemeenschap wordt besteed aan de prestaties van de selector, moeten we er toch naar streven om niet overdreven intensieve selectors te schrijven, indien mogelijk.
Je kunt deze selector een beetje verbeteren door te doen:
// Betere $ ('# container> invoer: uitgeschakeld');
Deze code beperkt de query eerst tot alle invoer op de pagina (in plaats van elk element). Sterker nog, we kunnen opnieuw het vind
of kinderen
methode.
$ ( '# Container') kinderen (inzet: disabled ');.
Het is belangrijk voor mij om te herhalen dat je je echt niet te veel zorgen hoeft te maken over de prestaties van de selector. Er zijn veel optimalisaties in jQuery die u kunnen helpen. Het is over het algemeen beter om je te concentreren op grotere ticketitems, zoals code-indeling en -structuur.
Als Sizzle bijvoorbeeld een selector zoals tegenkomt $ ('# box p')
, het is waar dat het van rechts naar links werkt, maar er is ook een snelle regex-optimalisatie die eerst bepaalt of het eerste deel van de selector een ID kaart
. Als dat zo is, gebruikt het dat als de context bij het zoeken naar de alineatags.
Desalniettemin is het altijd handig om te weten wat er achter de schermen gebeurt - tenminste op een erg laag niveau.