2009-09-11 12 views
5

Mam duże różnice w wydajności w zależności od sposobu wyrażania moich selektorów. Na przykład, spójrz na tych 2 selektorów, które wybrać dokładnie te same elementy:Wydajność selektora jQuery

A) someTableRow.find("td.someColumnClass").find("span.editMode").find("input") 
B) someTableRow.find("td.someColumnClass span.editMode input") 

spodziewałbym do B), aby być szybciej, ponieważ istnieje tylko 1 połączenie, ale w rzeczywistości jestem znalezieniem) wykonuje wokół 8 razy szybciej. Nie mam pojęcia, dlaczego, ktokolwiek ma jakiś wgląd? Dzięki

Odpowiedz

14

Zakładając używasz przynajmniej jQuery 1.3 (czyli z dodatkiem Sizzle), wydajność widzisz to spowodowane zmianami w którym DOM przemierzał. Od here:

włącznie jQuery 1.2.6 silnik selektor pracował w „odgórnie” (lub „od lewej do prawej”) sposób. jQuery 1.3.x (tj. Sizzle, który osadza jQuery) wprowadził podejście "oddolne" (lub "od prawej do lewej") do zapytania DOM.

W swoim drugim przykładzie ("td.someColumnClass span.editMode input") Trzask skutecznie robi to:

  1. uzyskać wszystkie input elementów wewnątrz someTableRow
  2. dla każdego elementu input znaleziony, przemierzać swoje drzewo przodkiem span elementów z class="editMode". Usuń elementy , które nie mają tych przodków, dla każdego znalezionego obiektu , przechodzimy przez jego drzewo przodków dla elementów td z class="someColumnClass". Usuń input elementy, które nie mają tych przodków

W pierwszym przykładzie jednak, twój każdy krok kwalifikacyjna są wyraźnie z każdym wywołaniu find(), określające kontekst i przejeżdżające dół stamtąd. Egzekwujesz podejście "odgórne". Jest to równoznaczne z przechodzącą w kontekście na każdym kroku, który jest generally considered a performance booster:

$('input', $('span.editMode', $('td.someColumnClass', someTableRow))) 
+0

Dzięki crescentfresh, ma sens. W rzeczywistości przeszliśmy do wersji 1.3.2 z wersji 1.2.6 i nie wiedziałem, dlaczego niektóre z przyzwoicie szybkich selektorów stały się wolniejsze (większość z nich była szybsza). Pytanie - które jest szybsze, przekazywane w kontekście w każdym punkcie lub przy użyciu połączonych wywołań find()? – JonoW

+0

Są one faktycznie równoważne. $ ('foo', 'bar') faktycznie zostanie przekierowany do $ ('bar'). find ('foo') w brzuchu jQuery. Przypuszczam, że wywołanie funkcji find() jawnie zapisuje kilka cykli procesora, ale nic, o czym można by pomyśleć. Zrób wszystko, co jest najbardziej czytelne dla twojego zespołu. Uważam, że jest bardzo czytelny;) –

+0

Fajnie, czuję, że find() jest dla mnie bardziej intuicyjny, więc użyję tego – JonoW

1

A to więcej połączeń, ale prostsze. B to jedno połączenie, ale bardziej złożone. W tym przypadku złożoność połączenia znacznie się zmniejsza - waży ilość połączeń.

2

Ponieważ redukujesz kontekst wyszukiwania.

W przypadku B, musi przeszukać każdy element DOM, aby sprawdzić, czy spełnia on kryteria.

W przypadku A, można szybko zdecydować, aby zignorować wszystko, co nie jest "td.someColumnClass", wtedy może wziąć ten podzestaw DOM i zignorować wszystko, czego nie ma w "span.editMode". Ma więc znacznie mniejszy zestaw elementów do przeszukiwania, aby znaleźć "dane wejściowe".

+1

Jak to "szybko zdecydować się zignorować ..." bez przechodzenia przez całe DOM dzieci SomeTableRow? Oba sprawdzają ten sam pełny zestaw elementów podrzędnych, jeden szuka td z pewnąKolumnClass, następnie analizuje tę listę dla zakresów z parametrem editMode, a następnie analizuje listę pod kątem wprowadzenia. Drugi szuka wszystkich trzech kryteriów w tym samym wyszukiwaniu na początkowej liście. – billjamesdev

+0

Ponieważ te dwa selektory mają identyczne znaczenie, nie widzę powodu, dla którego jQuery nie mógł użyć tej samej strategii w obu przypadkach. –

1

Sposób w jaki JQuery obsługuje selektory jest nieco inny niż w moim doświadczeniu.

Zredukowanie kontekstu wyszukiwania jest kluczem, jak wskazał Josh.

uważam za pomocą dwóch selektorów parametrów naprawdę szybkich

Jak to porównać prędkość mądry?

Nie potrzebujesz wszystkich vars tutaj, aby wyjaśnić, co robię.

var columnClasses = $('.someColumnClass'); 
var tableCell = $('td', columnclasses); 
var editMode = $('.editmode', tableCell); 
var spanInside = $('span', editMode); 
var inputFinally = $('input', spanInside); 

Dobroć,

Dan

1

Zrobiłem rozeznanie w jQuery wyboru wydajności siebie. Dużym problemem są odnośniki według nazwy klasy w Internet Explorerze. IE nie obsługuje getElementsByClassName - w związku z tym jQuery i inne frameworki "reimplementują" je w JavaScript, poprzez iterowanie przez wszystkie elementy DOM. Sprawdź poniższy blog analityczny na temat jQuery Selector Performance