Вот народ ушел в спор о производительности, но никто даже не попытался разобраться, а что под капотом... Производительность ведь искусственными бенчмарками меряют, ага...
Что ж, времена сейчас такиемногие на работу кодеров берут, которые даже интереса не имеют в глубь копать. Инженеров брать... - это устаревший подход, как выразился автор "популярного сайта", который прочел автор вопроса. Инженеры они дорогие, и найти их сложно, лучше кодер, пусть и не желающий на работе мозг включать, не говоря уж о желании в устройстве инструментов разбираться.
Говорить о том, что некие фичи устарели - крайне глупо, если знать, что они ведут себя иначе, чем более модные альтернативы. Предлагаю немного разобраться и начать с того что на поверхности:
-
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-кодера это будет незначительной потерей измеряемой в наносекундах. Используйте то что удобнее в каждой конкретной ситуации.