Selektory v JS (jQuery)

jQuery umožňuje vyhledávat prvky podle celé řady vlastností:

$('tag');
$('#id');
$('.class');
$('[property=value]');
$(':expression');

Je ale celkem rozdíl v rychlosti, jak jednotlivé selektory pracují.

jQuery nebo bez jQuery, toť otázka

Všechny moderní prohlížeče mají celou řadu metod, jak najít prvky ve stránce:

document.getElementById('id');
document.getElementsByName('name');
document.getElementsByTagName('tag');
document.getElementsByClassName('class')

Tyto metody jsou rychlejší než jejich jQuery alternativy, jednoduše proto, že jQuery musí nejprve pochopit řetězec, který jste funkci předali, a pak musí stejně použít buď tyto základní metody prohlížeče nebo své vlastní (které jsou výrazně pomalejší). Proto bude vždy document.getElementById(‚id‘) rychlejší než $(‚#id‘) i když je na zápis mnohonásobně delší.

Pokud tedy hledáte element jen podle jednoho selektoru (ID, tag, name nebo class), použijte metodu prohlížeče a – pokud potřebujete – nalezený prvek nebo prvky teprve předejte jQuery. A pokud to není potřeba, je lepší to napsat přímo v čistém JavaScriptu.

//pomalé
$('#id').hide();
//rychlejší
$(document.getElementById('id')).hide(); //nejrychlejší
document.getElementById('id')
    .style.display = 'none'

//hodně pomalé
val = $('[name|=username]').val();
//rychlejší
val = $(document.getElementsByName('username')
          .val();
//nejrychlejší
val = document.getElementsByName('username')[0]
          .value;

Nicméně často potřebujete hledat složitější výrazy, které tyto vestavěné funkce nepodporují a tak vám nezbude nic jiného než použít jQuery. Pokud ale jQuery (z jakéhokoliv důvodu) nechcete či nemůžete použít, máte ještě dvě možnosti:

  • většina moderních prohlížečů (tzn. cokoliv novějšího než IE7) nabízí ještě funkce document.querySelector() a document.querySelelectorAll(), které fungují podobně jako jQuery. Bohužel ale neexistuje žádná specifikace, takže každý prohlížeč může selektor zpracovat jinak. Některé prohlížeče ještě mají vlastní funkci $(), ale ta funguje obdobně (nepředvídatelně).
  • JS knihovna Sizzle nabízí hledání pomocí selektorů podobně jako jQuery pomocí funkce Sizzle(selektor) a vzhledem k tomu, že nic jiného nedělá, zpravidla odolá všem důvodům, proč nepoužít externí knihovnu (velikost, kompatibilita, apod.). A navíc funguje i na starších prohlížečích jako je IE6+, Opera 10+, a Android 2.x (které querySelektor nepodporují).
    Vše, co bude dále uvedeno, platí jak pro jQuery tak i pro Sizzle!

Unikátní ID

Nejrychlejší hledání je podle ID, protože to podle specifikace HTML může být na stránce jen jednou, a proto většina prohlížečů, když narazí na prvek s definovaným ID, tak si ho rovnou zapamatují – takže když se na něj pak zeptáte, rovnou ví, kde je.

A i pokud by ho necachovali, tak to bude rychlejší, protože ví, že když ho najdou, nemusí už hledat dál; naproti tomu při hledání podle jména nebo třídy je potřeba projít všechny prvky až do konce, protože jich může být víc.

Pokud tedy něco v jQuery hledáte a víte o tom, že se to nachází uvnitř prvku s ID, vždy ho do selektoru přidejte:

$('.selected'); //pomalé - prochází celý DOM
$('#mainmenu .selected'); //projde jen menu

Tagování

Typů prvků (DIV, SPAN, P, A, atd.) není tolik (alespoň těch běžně používaných) a hlavně se s každým zachází trochu jinak a proto si prohlížeče (většinou) vytváří hash tabulky podle typů prvků. Proto je druhá nejrychlejší metoda hledání podle TAGu.

Takže pokud v jQuery hledáte něco podle třídy nebo speciálního selektoru a víte, že to může být jen konkrétní typ prvku, vždy ho do selektoru přidejte:

$('.selected'); //pomalé - prochází celý DOM
$('li.selected'); //projde jen všechny seznam

K urychlení hledání pomocí typu prvku můžete použít i dvoukrokové hledání, pokud víte, že hledaný prvek se může nalézat jen uvnitř prvku konkrétního typu:

$('img.selected'); //musí projít všechny obrázky
                   //a zkontrolovat jejich třídu
$('li img.selected'); //prochází jen obrázky,
                      //které jsou v seznamech

Zde je ale potřeba trochu přemýšlet, protože pomocí selektoru ‚li img.selected‚ musí jQuery nejprve najít všechny položky seznamu (LI) a pak je postupně prohledat a hledat obrázky. Pokud tedy máte stránku plnou seznamů ale jen s pár obrázky, může být tento selektor naopak pomalejší. Naopak na stránce s galerií (kde jsou desítky obrázků), ale vy hledáte jen ikonku z menu (které je – jako jediné – udělané pomocí UL/LI), bude přidání LI do selektoru velkým urychlením.

Poznámka: Všechny prohlížeče ještě nabízejí pro určité typy ještě tzv. kolekce. Pokud například potřebujete projít všechny obrázky, můžete použít kolekci document.images. Další známé kolekce jsou např. document.links nebo document.forms. Pro pokročilejší práce můžete najít načtené CSS definice a JS skripty v document.scripts a document.styleSheets. A samozřejmě nesmíme zapomenout na přímé odkazy na document.head a document.body. A k HTML rootu se nejrychleji dostanete přes document.head.parentNode.

Třídní boj

Pokud nemůžete použít ani ID, ani tag, další nejvhodnější selektor je třída. Ta sice nijak moc element nespecifikuje a jQuery (resp. prohlížeč) musí vždy projít všechny prvky, ale na druhou stranu, jak už bylo řečeno, pro hledání elementů podle třídy existuje nativní metoda prohlížeče, takže je mnohem rychlejší – v porovnání s hledáním podle vlastnosti (např. ‚[type=password]‘) nebo speciálního selektoru (např. ‚:visible‘).

Vždy je tedy lepší přidat prvku třídu, podle které ho najdete rychleji:

//pomalé - prochází všechny prvky
//a kontroluje jejich typ
<input type="password" />
<script>$('[type=password]').prettify();</script>

//rychlejší - použije nativní hledání třídy
<input type="password" class="password" />
<script>$('.password').prettify();</script>

Stejně tak to můžete udělat i v kódu pro pozdější nalezení ovlivněných prvků:

//pomalé - prochází všechny prvky
// a kontroluje jejich viditelnost
$(el).children('img').show();
...
$(el).children('img:visible').hide();

//rychlejší - hledá podle třídy
$(el).children('img').show().addClass('hide-me');
...
$(el).children('img.hide-me')
           .hide().removeClass('hide-me');

Ostatní selektory

Ostatní selektory, které jsou definované v CSS (např. „[type=password]“, „:first-child“, apod.) a své vlastní (např. „:visible“) zpracovává jQuery prostě tak, že v cyklu prochází nalezené elementy a kontroluje jejich vlastnosti (např. hodnoty display a visibility pro :visible) – což znamená, že kód je napsaný v JavaScriptu a tudíž není nijak výkonný.

Vždy se proto snažte využití těchto selektorů vyhnout (např. použitím ID nebo třídy) nebo alespoň omezit množství prohledávaných prvků pomocí výše uvedených postupů:

//od nejpomalejšího k nejrychlejšímu
$(':visible').hide();
$('.to-be-hidden:visible').hide();
$('div.to-be-hidden:visible').hide();
$('div .to-be-hidden:visible').hide();
$('#items .to-be-hidden:visible').hide();
$('#item546:visible).hide();

Vlastní hledání

Možná vás teď napadlo, že z výše popsaného vyplývá, že jQuery je vlastně v hledání dost pomalé a že by možná bylo rychlejší napsat si vlastní metody pro hledání s použitím nativních metod – nebylo!

I když je jQuery pomalejší než prohlížeč, na vývoji jQuery se podíleli desítky lidí a díky nim je v hledacích postupech celá řada vylepšení a oprav chyb. A kdybyste napsali vlastní metody, budete muset řešit stejné problémy, které jsou již v jQuery vyřešeny.

Neříkám, že pro konkrétní jednoduchý případ nebude rychlejší napsat si vlastní metodu, ale ve vším měřítku se vám vždy vyplatí spoléhat se na jQuery.

//pomalejší
$(menuItem).parent().find('ul').hide();

//rychlejší
function hideSubmenu(menuItem) {
    var parent, submenu;
    parent = menuItem.parentNode;
    submenu = parent.getElementsByTagName('ul');
    submenu[0].style.display = 'none';
}

Pokud potřebujete, můžete si napsat vlastní selektory.

jQuery vs. CSS

Pozor na to, že v CSS neplatí to, co jsem zde napsal o jQuery! jQuery totiž zpracovává pravidla zleva doprava zatímco CSS bere pravidla zprava doleva.

$('.highlight'); //pomalé - musí projít všechny
                 // prvky a ověřit třídu
$('#menu .highlight'); //rychlé - projde jen menu

.highlight { background: yellow; } //rychlé
     //prostě aplikuje na element, pokud má třídu
#menu .highlight { background:yellow } //pomalé
     //musí totiž ověřit, jestli je element
     //uvnitř menu, což znamená projít všechny
     //jeho rodiče!

Více viz optimalizace selektorů v css.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *

Tato stránka používá Akismet k omezení spamu. Podívejte se, jak vaše data z komentářů zpracováváme..