Хороші способи покращити продуктивність селектора jQuery?


74

Я шукаю будь-який спосіб, як покращити ефективність селектора виклику jQuery. Зокрема такі речі:

Є чи $("div.myclass")швидше$(".myclass")

Я б подумав, що це може бути, але я не знаю, чи достатньо розумний jQuery, щоб спочатку обмежити пошук за назвою тегу і т. Д. У когось є ідеї щодо того, як сформулювати рядок селектора jQuery для найкращої роботи?

Відповіді:


36

Немає сумнівів, що фільтрація за назвою тегу спочатку набагато швидша, ніж фільтрація за назвою класу.

Так буде до тих пір, поки всі браузери не реалізують getElementsByClassName спочатку, як у випадку з getElementsByTagName.


Але навіть якщо браузер реалізує цю функцію, все одно швидше фільтрувати за назвою тегу теж правильно?
Гофман

Я оновив componentnthouse.com/article-19 із відповіді Джеффа, щоб використовувати найновіший jQuery, здається, що з другого тесту A і B мають однакову продуктивність в Opera 10 та firefox 3.5. Я не міг змусити це працювати на IE8 (хоча я багато не пробував). Тож, схоже, я помилився у своєму попередньому коментарі.
Гофман

@hoffmann, мабуть, ні. Якщо ми припустимо, що обидві ці функції реалізовані з b-деревами, я не розумію, чому getElementsByClassName буде повільнішим ... Вам все одно доведеться будувати індекс, перш ніж мати можливість використовувати цю функцію ...
Еван Керролл

@AlienWebguy: Суть цієї відповіді полягає в тому, що деякі браузери не підтримують getElementsByClassName, а це означає, що кожен елемент на сторінці повинен бути перевірений для класу. Майте на увазі, що ця відповідь була дана також у 2008 році. ; o)
user113716

1
@AlienWebguy: ваш тест не точно відображає велику сторінку з великою кількістю елементів DOM. Ваш тест швидший завдяки простому набору фільтрів, а не швидшому пошуку.
Арен

14

У деяких випадках ви можете пришвидшити запит, обмеживши його контекст. Якщо у вас є посилання на елемент, ви можете передати його як другий аргумент для обмеження обсягу запиту:

$(".myclass", a_DOM_element);

повинно бути швидше ніж

$(".myclass");

якщо у вас вже є елемент_DOM_element, і він значно менший за весь документ.


2
Наскільки я пам’ятаю, $('.myclass', a_DOM_element)jQuery перекладає на / дзвінки, $(a_DOM_element).find('.myclass')тому може бути трохи швидше просто використовувати, find()а не встановлювати контекст селектора, як у вашому першому прикладі.
Девід каже, щоб відновити Моніку

5

Як зазначив Рейд вище, jQuery працює знизу вгору. Хоча

це означає $('#foo bar div'), що набагато повільніше, ніж$('bar div #foo')

Справа не в цьому. Якби у вас було, #fooви все одно нічого перед цим не поміщали б у селектор, оскільки ідентифікатори повинні бути унікальними.

Справа в тому:

  • якщо ви subselecting що - небудь з елемента з ідентифікатором потім виберіть пізніше першого , а потім використовувати .find, і .childrenт.д.:$('#foo').find('div')
  • ваша найлівіша (перша) частина селектора може бути менш ефективною масштабуванням до самої правої (останньої) частини, яка повинна бути найбільш ефективною - тобто, якщо у вас немає ідентифікатора, переконайтеся, що шукаєте, $('div.common[slow*=Search] input.rare')а не $('div.rare input.common[name*=slowSearch]')- оскільки це не ' t завжди застосовне, переконайтеся, що форсуйте порядок селектора, розділивши відповідним чином.

5

Для того, щоб повністю зрозуміти, що швидше, ви повинні зрозуміти, як працює синтаксичний аналізатор CSS.

Селектор, який ви передаєте, ділиться на впізнавані частини за допомогою RegExp, а потім обробляє поштучно.

Деякі селектори, такі як ID та TagName, використовують швидше вбудовану реалізацію браузера. У той час як інші, як клас та атрибути, запрограмовані окремо, тому вони набагато повільніші, вимагаючи перегляду вибраних елементів та перевірки кожного імені класу.

Тож так, щоб відповісти на ваше запитання:

$ ('tag.class') швидше, ніж просто $ ('. class'). Чому? У першому випадку jQuery використовує реалізацію власного браузера, щоб відфільтрувати виділення до потрібних вам елементів. Тільки тоді він запускає повільнішу реалізацію .class, фільтруючи до того, про що ви просили.

У другому випадку jQuery використовує свій метод для фільтрації кожного елемента, захоплюючи клас.

Це поширюється далі, ніж jQuery, оскільки всі бібліотеки javascript базуються на цьому. Єдиним іншим варіантом є використання xPath, але в даний час він не дуже добре підтримується серед усіх браузерів.



3

Додам, що в 99% веб-програм, навіть важких додатків Ajax, швидкість з’єднання та відповідь веб-сервера впливатимуть на продуктивність вашої програми, а не на javascript. Я не кажу про те, що вам слід писати навмисно повільний код, або що загалом усвідомлення того, що речі можуть бути швидшими за інші, не є хорошим.

Але мені цікаво, чи намагаєтесь ви вирішити проблему, яка насправді ще не існує, чи навіть оптимізуєте щось, що може змінитися найближчим часом (скажімо, якщо більше людей почнуть користуватися браузером, що підтримує getElementsByClassName()функцію згадані раніше), завдяки чому ваш оптимізований код насправді працює повільніше.


3

Інше місце, де слід шукати інформацію про ефективність, - це сторінка аналізу продуктивності селекторів Уго Відаля Тейшейри.

http://www.componenthouse.com/article-19

Це дає хороший пробіг швидкостей для селектора за ідентифікатором, селектора за класом та імені префікса селектора.

Найшвидшими селекторами за ідентифікатором було: $ ("# id")

Найшвидшим селектором за класом було: $ ('tag.class')

Тож префікс за тегом допоміг лише при виборі за класом!


0

Я був у деяких списках розсилки jQuery, і з того, що я там читав, вони, швидше за все, фільтруються за назвою тегу, а потім за назвою класу (або навпаки, якщо це було швидше). Вони нав’язливі щодо швидкості і використовуватимуть що завгодно, щоб отримати трохи продуктивності.

Я б насправді не хвилювався з цього приводу надто сильно, якщо ви не запускаєте цей селектор тисячі разів на секунду.

Якщо ви дійсно стурбовані, спробуйте зробити порівняльний аналіз і подивіться, що швидше.


0

Подумайте про використання бібліотеки Олівера Стіла для послідовного виклику методів з часом, а не відразу.

http://osteele.com/sources/javascript/ послідовно/

Метод "врешті-решт" допомагає вам викликати метод через певний проміжок часу з моменту його першого виклику. Метод "послідовно" дозволяє поставити в чергу кілька завдань протягом певного періоду часу.

Дуже корисний!


0

Великий наконечник від питання я запитав: Використовуйте стандартні CSS селектори всюди , де це можливо. Це дозволяє jQuery використовувати API Selectors . Відповідно до тестів, проведених Джоном Резігом , це призводить до майже рідної продуктивності для селекторів. Таких функцій, як :has()і :contains()слід уникати.

З моїх досліджень підтримка API Selectors була представлена ​​з jQuery 1.2.7, Firefox 3.1, IE 8, Opera 10, Safari 3.1.


0

Якщо я не помиляюся, jQuery також є двигуном знизу вгору. Це означає $('#foo bar div'), що набагато повільніше, ніж $('bar div #foo'). Наприклад, $('#foo a')пройде всі aелементи на сторінці і перевірить, чи є у них предком #foo, що робить цей селектор надзвичайно неефективним.

Можливо, Resig вже оптимізував для цього сценарію (мене це не здивувало б, якщо він це зробив - я вважаю, що він це зробив у своєму двигуні Sizzle, але я не впевнений на 100%)


0

Я вважаю, що вибір за ідентифікатором спочатку завжди швидший:

$("#myform th").css("color","red");

повинно бути швидше ніж

$("th").css("color","red");

Однак цікаво, наскільки допомагає ланцюжок, починаючи з посвідчення особи? Це

$("#myform").find("th").css("color","red")
.end().find("td").css("color","blue");

швидше за це?

$("#myform th").css("color","red");
$("#myform td").css("color","blue");

З мого досвіду, $ ("# myform"). Find ("th") також швидший, ніж $ ("# myform th") через те, що перший безпосередньо делегується рідному getElementByID браузера. Мережа також допомагає, але по суті накладні витрати - це вартість другого виклику getElementByID, який зазвичай є незначним.
peakxu

sizzle, движок селектора jQuery працює справа наліво. Отже, ваш перший приклад: $ ("# myform th"). Css ("color", "red"); вперше знаходить кожного го на сторінці. Потім він переглядає їх і переглядає батьків для кожного з них, поки не знайде елемент з ідентифікатором myForm. Теоретично тоді ваш другий приклад: $ ("th"). Css ("color", "red"); повинні бути швидшими, ніж ваші перші, оскільки це просто ітерація над цим, а не огляд батьків.
Кріс Спіттлз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.