Hoe jQuery-beginners hun code kunnen testen en verbeteren

jQuery's komst heeft het proces gemaakt om JavaScript lachwekkend gemakkelijk te maken. Maar u zult merken dat het wijzigen van kleine wijzigingen in de code de leesbaarheid en / of prestaties aanzienlijk verbetert. Hier zijn enkele tips om u op weg te helpen om uw code te optimaliseren.


Het platform opzetten

We hebben een solide platform nodig om onze tests uit te voeren. Dit is de HTML-markering voor de testpagina waarin we al onze tests uitvoeren:

     Prestatieverbetering testen - Siddharth / NetTuts+   

Een beetje tekst hier

  • Oh Hallo daar!

Er is hier niets bijzonders; gewoon een aantal elementen die we kunnen richten en testen. We gebruiken Firebug om de tijden hier te loggen. profiel begint het proces, en profileEnd stopt het en noteert hoeveel tijd de taak in beslag nam. Ik gebruik meestal de belangrijkste profielmethode van Firebug, maar voor onze sluwe doelen is dit voldoende.


1. Detecteer of een element bestaat

Zoals vaak het geval is, dient u een enkel scriptbestand met uw code voor alle pagina's op uw site. Dit is meestal code die vaak acties uitvoert op niet-bestaande elementen op de huidige pagina. Hoewel jQuery dergelijke problemen heel gracieus behandelt, betekent dit niet dat je eventuele problemen gewoon kunt negeren. Als u de methoden van jQuery in een lege verzameling aanroept, worden ze namelijk niet uitgevoerd.

Voer als best practice alleen code uit die van toepassing is op de pagina die op dat moment is geladen, in plaats van dat u al uw code samenvoegt in één klaar-check voor één document en deze aan de klant aanbiedt.

Laten we naar het eerste scenario kijken:

 console.profile (); var ele = $ ("# somethingThatisNotHere"); ele.text ("Enkele tekst"). slideUp (300) .addClass ("bewerken"); $ ( "# MainItem"); console.profileEnd (); // Hier nog meer geweldige code die de grond breekt..

Firebug's spuugt het volgende resultaat uit:

Laten we dit keer eens kijken of het element waarop we acties willen uitvoeren al bestaat voordat we dit doen.

 console.profile (); var ele = $ ("# somethingThatisNotHere"); if (ele [0]) ele.text ("Some text"). slideUp (300) .addClass ("bewerken");  $ ("# mainItem"); console.profileEnd (); // Hier nog meer geweldige code die de grond breekt.. 

En de resultaten:

Zien? Het is vrij eenvoudig, to the point en krijgt de klus geklaard. Merk op dat u niet hoeft te controleren of een element bestaat voor elk bit van uw code. U zult op uw pagina merken dat bepaalde grotere delen in het algemeen van deze methode zullen profiteren. Gebruik je oordeel hier.


2. Gebruik Selectors effectief

Probeer een ID te gebruiken in plaats van een klas te passeren.

Dit is een groot onderwerp dus ik zal het zo beknopt mogelijk houden. Probeer eerst een ID te gebruiken in plaats van een klasse te passeren wanneer je in selectors deelt. jQuery maakt rechtstreeks gebruik van de native getElementById methode om een ​​element te vinden op ID, terwijl het in het geval van een klasse een aantal interne voodoo moet doen om het te verkrijgen, tenminste in oudere browsers.

We zullen kijken naar de verschillende selectors die u kunt gebruiken om de 2e te selecteren li element. We zullen elk van hen testen en hoe ze de uitvoering wijzigen.

De eerste methode, de gemakkelijkste methode, is om deze eenvoudig te targeten met behulp van de gekozen klasse. Laten we eens kijken wat de profiler van Firebug terugkrijgt.

 console.profile (); $ ( "Geselecteerd."); console.profileEnd (); 

En het resultaat: 0.308ms. Vervolgens geven we een voorvoegsel voor een tagnaam om het te beperken. Op deze manier kunnen we onze zoekopdracht verfijnen door eerst alleen de geselecteerde DOM-elementen te targeten, met document.getElementsByTagName.

 console.profile (); $ ( "Li.selected"); console.profileEnd (); 

En het resultaat: 0,291 ms. Ruwweg 0,02 ms afgeschaafd. Dit is verwaarloosbaar vanwege het feit dat we in Firefox testen; Er moet echter worden opgemerkt dat deze prestatieverbetering aanzienlijk hoger zal zijn in oudere browsers, zoals Internet Explorer 6.

Vervolgens dalen we af van de ID van het bovenliggende element.

 console.profile (); $ ("# someList .geselecteerd"); console.profileEnd (); 

En het resultaat: 0.283ms. Laten we proberen een beetje specifieker te zijn. We specificeren ook het type element naast de ID van de voorouder.

 console.profile (); $ ("# someList li.selected"); console.profileEnd (); 

En het resultaat: 0,275 ms. Nog een klein deel afgeschoren. Laten we tenslotte het gewoon rechtstreeks richten met een ID voor.

 console.profile (); $ ( "# MainItem"); console.profileEnd (); 

En het resultaat: 0,165ms. Indrukwekkend! Dit laat je zien hoeveel sneller het is om native methoden uit te voeren. Merk op dat, hoewel moderne browsers voordeel kunnen halen uit dingen als getElementsByClassName, oudere browsers dit niet kunnen - wat resulteert in veel langzamere prestaties. Houd hier altijd rekening mee bij het coderen.


3. Account voor Sizzle's Parsing Model en Scopes toevoegen

Sizzle, de selector-engine die jQuery gebruikt - gebouwd door John Resig - ontleedt selectors van rechts naar links, wat een paar onverwachte ketens van parsing oplevert.

Overweeg deze selector:

 $ ("# someList .geselecteerd"); 

Wanneer Sizzle een dergelijke selector tegenkomt, bouwt het eerst de DOM-structuur op, gebruikt de selector als root, verwijdert items die niet de vereiste klasse hebben en, voor elk element met de klasse, controleert het of zijn ouder een ID heeft van someList.

Om dit te verantwoorden, moet u ervoor zorgen dat het meest rechtse deel van uw selector zo specifiek mogelijk is. Bijvoorbeeld door op te geven li.selected in plaats van .gekozen, u vermindert het aantal knooppunten dat moet worden gecontroleerd. Dit is de reden waarom de prestaties in de vorige sectie zijn gesprongen. Door extra beperkingen toe te voegen, vermindert u effectief het aantal knooppunten dat moet worden gecontroleerd.

Om de manier waarop elementen worden verkregen beter te kunnen afstemmen, moet je kijken naar het toevoegen van een context voor elke aanvraag.

 var someList = $ ('# someList') [0]; $ (". selected", someList);

Door een context toe te voegen, verandert de manier waarop het element wordt doorzocht volledig. Nu, het element dat de context verschaft - someList in ons geval - wordt eerst gezocht naar, en als het eenmaal is verkregen, worden onderliggende elementen die niet over de vereiste klasse beschikken verwijderd.

Merk op dat het over het algemeen een goede gewoonte is om een ​​DOM-element door te geven als de context van uw jQuery-selector. Het gebruik van een context is het nuttigst wanneer het in een variabele is opgeslagen. Anders kun je het proces stroomlijnen en gebruik find () - wat jQuery zelf doet onder de motorkap.

 $ ( '# SomeList') vinden ( 'geselecteerd..');

Ik zou willen zeggen dat de prestatieverbetering duidelijk zal worden gedefinieerd, maar dat kan ik niet. Ik heb testen op een aantal browsers uitgevoerd en of de benaderende prestaties van die van de vanille-versie afhangen van een aantal factoren, inclusief of de browser specifieke methoden ondersteunt.


4. Vermijd Query-afval

Wanneer je door de code van iemand anders bladert, zul je dit vaak vinden.

 // Andere code $ (element) .doSomething (); // Meer code $ (element) .doSomethingElse (); // Nog meer code $ (element) .doMoreofSomethingElse (); 

Doe dit alsjeblieft niet. Ooit. De ontwikkelaar maakt dit 'element' steeds opnieuw. Dit is verspilling.

Laten we eens kijken hoeveel tijd dergelijke verschrikkelijke code kost om te draaien.

 console.profile (); $ ( "# MainItem") te verbergen ().; $ ( "# MainItem") val ( "Hello."); $ ("# mainItem"). html ("Oh, hey there!"); $ ( "# MainItem") geven (.); console.profileEnd (); 

Als de code zoals hierboven gestructureerd is, kunt u de een na de ander gebruiken zoals:

 console.profile (); $ ("# mainItem"). hide (). val ("Hallo"). html ("Oh, hey there!"). show (); console.profileEnd ();

Door te ketenen wordt het oorspronkelijk ingevoerde element overgenomen en wordt een referentie doorgegeven aan elke volgende oproep die de uitvoeringstijd verkort. Anders wordt elke keer een nieuw jQuery-object gemaakt.

Maar als in tegenstelling tot hierboven, de secties die verwijzen naar het element niet gelijk zijn, moet je het element cachen en dan dezelfde bewerkingen doen als eerder.

 console.profile (); var elem = $ ("# mainItem"); elem.hide (); // Sommige code elem.val ("Hallo"); // Meer code elem.html ("Oh, hey there!"); // Nog meer code elem.show (); console.profileEnd (); 

Zoals uit de resultaten blijkt, vermindert caching of chaining de uitvoeringstijd aanzienlijk.


5. Voer DOM-manipulatie intelligenter uit

Het suggereren van niet-traditionele DOM-manipulatie in mijn eerdere artikel trok een beetje flak van een paar mensen voordat werd aangetoond dat de prestatieverbetering echt de moeite waard is. We zullen het nu zelf testen.

Voor de test maken we 50 li elementen, en voeg ze toe aan de huidige lijst en bepaal hoeveel tijd het kost.

We zullen eerst de normale, inefficiënte methode beoordelen. We voegen in feite het element toe aan de lijst elke keer dat de lus wordt uitgevoerd.

 console.profile (); var list = $ ("# someList"); for (var i = 0; i<50; i++)  list.append('
  • Item # '+ i +'
  • '); console.profileEnd ();

    Laten we kijken hoe het ging, zullen we?

    Nu volgen we een iets ander pad. We voegen in feite de vereiste HTML-reeks toe aan een variabele firs en vervolgens de DOM slechts één keer opnieuw.

     console.profile (); var list = $ ("# someList"); var items = ""; for (var i = 0; i<50; i++) items += '
  • Item # '+ i +'
  • '; list.append (items); console.profileEnd ();

    Zoals verwacht is de benodigde tijd aanzienlijk afgenomen.

    Als u jQuery gebruikt als vervanging voor getElementById, maar nooit een van de aangeboden methoden gebruikt, doet u het verkeerd.

    Als je verder wilt gaan, vraag jezelf dan af of je echt een nieuw jQuery-object moet maken om een ​​bepaald element te targeten? Als u jQuery gebruikt als vervanging voor document.getElementById, maar nooit een van de aangeboden methoden gebruikt, doet u het verkeerd. In dit geval kunnen we wegkomen met onbewerkte JS.

     console.profile (); var list = document.getElementById ('someList'); var items = "; for (var i = 0; i<50; i++) items += '
  • Item # '+ i +'
  • '; list.innerHTML = items; console.profileEnd ();

    Een paar kanttekeningen

    U zult merken dat het verschil in uitvoeringstijd tussen de geoptimaliseerde en de niet-geoptimaliseerde code in de fractie van een milliseconde bereik ligt. Dit komt omdat ons testdocument erg klein is met een onmogelijk klein aantal knooppunten. Zodra je begint te werken met sites op productieniveau met een paar duizend knooppunten erin, zal het echt kloppen.

    Merk ook op dat ik in de meeste van deze tests gewoon toegang heb tot de elementen. Wanneer u begint met het toepassen van de juiste functies, neemt de delta in de uitvoeringstijd toe.

    Ik begrijp ook dat dit niet de meest wetenschappelijke methoden zijn om de prestaties te testen, maar om een ​​algemeen beeld te krijgen van de invloed van elk van deze veranderingen op de prestaties, denk ik dat dit voldoende is.

    Ten slotte zullen in de meeste van uw web-apps de verbindingssnelheid en reactietijd van de betreffende webserver meer een rol spelen bij de prestaties van uw app dan de tweaks in de code die u maakt. Desalniettemin is dit nog steeds belangrijke informatie en zal het u helpen de weg te vinden als u probeert zoveel mogelijk prestaties uit uw code te halen.


    Dat is alles Mensen

    En we zijn klaar. Een paar punten om in gedachten te houden wanneer u probeert uw code te optimaliseren; dit is natuurlijk niet de allesomvattende lijst van tweaks en de punten hoeven niet noodzakelijkerwijs van toepassing te zijn op alle situaties. Hoe dan ook, ik zal de reacties nauwlettend in de gaten houden om te lezen wat je over het onderwerp te zeggen hebt. Elke fout die je hier ziet? Stuur me een regel hieronder.

    Vragen? Leuke dingen om te zeggen? Kritiek? Klik op het gedeelte Opmerkingen en laat een opmerking achter. Happy codering!