DredWulf
@DredWulf

Устарел ли getElementsBy* и чем лучше querrySelector?

На одном довольно популярном сайте про JS прочел, что getElementsBy*... устаревший подход. Что вы про это думаете?
  • Вопрос задан
  • 2370 просмотров
Решения вопроса 1
bingo347
@bingo347 Куратор тега JavaScript
Crazy on performance...
Вот народ ушел в спор о производительности, но никто даже не попытался разобраться, а что под капотом... Производительность ведь искусственными бенчмарками меряют, ага...
Что ж, времена сейчас такие
многие на работу кодеров берут, которые даже интереса не имеют в глубь копать. Инженеров брать... - это устаревший подход, как выразился автор "популярного сайта", который прочел автор вопроса. Инженеры они дорогие, и найти их сложно, лучше кодер, пусть и не желающий на работе мозг включать, не говоря уж о желании в устройстве инструментов разбираться.

Говорить о том, что некие фичи устарели - крайне глупо, если знать, что они ведут себя иначе, чем более модные альтернативы. Предлагаю немного разобраться и начать с того что на поверхности:
- getElementById и querySelector возвращают конкретную ноду в единственном экземпляре
- querySelectorAll и getElementsByName возвращает статичную коллекцию NodeList
- getElementsByClassName, getElementsByTagName и getElementsByTagNameNS возвращают динамическую коллекцию HTMLCollection
Как видим результат у разного апи различен, а значит и говорить, что некоторые из них устарели - глупо.
Правда тут есть забавный момент
в спеке HTMLCollection отмечен как "исторический артефакт", который не стоит использовать при проектировании нового апи. Но заметка эта не для веб-разработчиков, а для тех кто проектирует новое DOM апи.

С устареванием вроде разобрались, но в вопросе еще есть часть "чем лучше". И тут есть теория, что getElementsBy* быстрее querySelector*. Чисто теоретически звучит логично, querySelector* должен делать полный поиск по дереву со сложностью O(n), а getElementsBy* могут использовать индексы на базе HashMap и получать данные со сложностью O(1), тут и особенности HTMLCollection будут кстати, так как можно не копировать коллекцию, а отдавать одну и ту же (и браузеры действительно так делают). Но без пруфов теория так и останется теорией.
И бенчмарки - так себе пруф
Хотя направлять инвесторов в нужную сторону - самое то. Проблема бенчмарков, что можно написать их так, что любая из сравниваемых сторон заметно обгонит другую. Дело техники. Например BubbleSort с O(n2) при определенных условиях в чистую уделывает MergeSort и QuickSort с их O(n×log2n), а именно при n=20 или меньше, 400 простых memswap в наглую рвут 87 рекурсивных операций с memcpy внутри
Гораздо лучше тут выглядят исходники. И я выбрал исходники chromium, как самого распространенного:
- getElementsBy* методы все как один обращаются к некой шаблонной функции EnsureCachedCollection, которая в свою очередь обращается к некоему NodeLists кэшу, устроенному внутри действительно как HashMap или что-то наподобие. Никакого поиска тут нет, просто берутся готовые значения, сложность у всего этого действительно константная O(1).
- querySelector* используют абстракцию SelectorQuery, которая и в самом деле делает поиск по DOM. Но данный поиск неплохо оптимизирован и обвешан кэшами. Притом CSSOM использует абсолютно тот же алгоритм поиска DOM нод для каждого селектора в css.
Для примера
в подключенных на странице этого вопроса стилях более 1600 правил (некоторые из которых потенциально могут содержать несколько селекторов), полная обработка стилей из этого файла заняла на моей машине (Ryzen 3600 в стоке) чуть больше 9 мс. Если все это немного округлить, то понадобится 15000 querySelectorAll подряд, притом с разными селекторами, чтоб был промах кэша, дабы я ощутил заметную глазу задержку в ~100мс


На этом спор думаю можно закрыть. querySelector* методы действительно могут быть медленнее, но чтоб убить ими производительность, нужно очень постараться. На фоне того, что пишут кривые ручки среднестатистического дешевого js-кодера это будет незначительной потерей измеряемой в наносекундах. Используйте то что удобнее в каждой конкретной ситуации.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@eandr_67
web-программист (*AMP, Go, JavaScript, вёрстка).
Нет, не устарел: да, querySelector и querySelectorAll намного универсальнее (почти jQuery), но из-за своей универсальности могут быть чуть медленеее, чем специализированные getElementsBy*.
Ответ написан
@zkrvndm Куратор тега JavaScript
Софт для автоматизации
Да, морально устарели, так как потенциальные выигрыши по времени при поиске не стоят ровном счетом ничего на фоне тех вызовов, что бросает типовой говнокод современным браузерам и процессорам. Что толку оптимизировать такие мелочи, если какая-нибудь сторонняя либа на вашем сайте кушает в миллионы раз больше ресурсов?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы