Jump to content

Плюсы и минусы мышления в стиле XPath


psywalker
 Share

Recommended Posts

SelenIT,

Кстати, про specified я только сейчас узнал, как-то пользоваться не доводилось :).

А я вот раньше как раз бывало им пользовался) Полезная штука всё же. :)

Впрочем, имхо, это уже оффтопик (хотя и безумно интересный). Может, есть смысл завести новую тему а-ля "Плюсы и минусы мышления в стиле XPath" где-нибудь во Флейме?

Конечно же, дружище, такие вещи даже не спрашиваются а делаются, сразу же и безоговорочно. Мне бы очень было интересно почитать такую тему :)

s0rr0w,

А мышление? querySelector - инструмент для ленивых, и скорость работы у него соответствующая. С ростом сложности кода задача оптимизации будет стоять все острее и острее.

Блииин, а я только начал им пользоваться...так порадовал...эхх :(

Link to comment
Share on other sites

Продолжение темы Javascript > 108 атрибутов!

Хм... во всех статьях про Selectors API, что мне попадались, как раз скорость приводят как главный плюс...

Бенчмарк: http://jsperf.com/queryselectorall-vs-getelementsbytagname

Картина одинаковая в Хроме и ФФ.

Блииин, а я только начал им пользоваться...так порадовал...эхх :(

На мелких проектах пофиг. Но на чем-то более серьезном этот тип мышления приводит к весьма противоречивому результату: вместо упрощения работы будет постоянная работа над оптимизацией запросов. И где профит?

  • Like 1
Link to comment
Share on other sites

s0rr0w, спасибо за тему и поучительную ссылку!

Читал статью Николаса Закаса с объяснениями, откуда такая разница, много думал...

Настоящая причина, почему getElementsByTagName() настолько быстрее, чем querySelectorAll() — из-за различия между "живым" и статическим объектами NodeList. Хотя, я уверен, это еще есть куда оптимизировать, но не делать ничего заранее для "живого" NodeList — всяко быстрее, чем делать всю предварительную работу при создании статического NodeList. Выбор того или иного метода сильно зависит от того, что вы хотите сделать. Если вы просто ищете элементы по имени тега и вам не нужен "мгновенный снимок" DOM-структуры, то нужно использовать getElementsByTagName(). Если вам нужен "мгновенный снимок" результата выборки или вы используете более сложный CSS-запрос, лучше использовать querySelectorAll().

Не совсем понимаю, почему результат выборки по селектору "обязан быть" статическим. И вообще, откуда и для чего взялся этот "статический NodeList"? Какие у него преимущества (кроме защиты от угрозы поймать бесконечный цикл при модификации DOM, как в примере у того же Николаса), что они оправдывают такой проигрыш в скорости? Может, на каком-нибудь новом повороте логики скрипта можно отыграть это упущенное время взад, используя этот "мгновенный снимок" структуры в качестве этакого кеша?

Link to comment
Share on other sites

Не совсем понимаю, почему результат выборки по селектору "обязан быть" статическим. И вообще, откуда и для чего взялся этот "статический NodeList"? Какие у него преимущества (кроме защиты от угрозы поймать бесконечный цикл при модификации DOM, как в примере у того же Николаса), что они оправдывают такой проигрыш в скорости? Может, на каком-нибудь новом повороте логики скрипта можно отыграть это упущенное время взад, используя этот "мгновенный снимок" структуры в качестве этакого кеша?

Мне кажется, что это сделано не спроста, а для того, чтобы не просаживаться еще больше по скорости.

Статический nodeList взялся из документации, в которой написано черным по белому

The NodeList object returned by the querySelectorAll() method must be static, not live ([DOM-LEVEL-3-CORE], section 1.1.1). Subsequent changes to the structure of the underlying document must not be reflected in the NodeList object. This means that the object will instead contain a list of matching Element nodes that were in the document at the time the list was created.

querySelectorAll не быстры из-за того, что ему приходится перебирать ВСЕ или почти все ноды. Оптимизировать запрос можно, но это будет затратно по протребляемой памяти. Если бы он был еще и живым вдобавок, то простой скрипт модификации дерева по списку, который вернул querySelectorAll, запускал бы ровно столько процедур поиска, сколько и модификаций было. А так как граната в руках обезъян всегда стреляет, то решили на уровне спецификации не допускать бомбы в скриптах.

  • Like 1
Link to comment
Share on other sites

Статический nodeList взялся из документации
Меня интересовало, как он в документацию попал (с) :) Но
Если бы он был еще и живым вдобавок, то простой скрипт модификации дерева по списку, который вернул querySelectorAll, запускал бы ровно столько процедур поиска, сколько и модификаций было.
логично объясняет резоны. Еще раз большое спасибо за полезную и познавательную информацию!
Link to comment
Share on other sites

Братва, а объясните мне пожалуйста следующие вещи:

1. То, что getElementsByTagName() живой, это я понимаю. Т.е. возвращаемый им массив элементов живой и в случае их удаления из ДОМ-а этот "живой" массив тоже будет меняться, как бы удаляя выбывший из игры элемент, пральна?

2. А что тогда происходит с querySelectorAll() в этом плане? Почему он НЕ живой? Т.е. если я, например выбрал все дивы в контейнере, то получаю я тоже массив ведь? Или это не массив?

А если один из этих дивов удаляется из ДОМ-а, то что происходит с массивом, полученным с помощью querySelectorAll()?

3. Что означает фраза ""мгновенный снимок" DOM-структуры"?

Link to comment
Share on other sites

почему же так плохо мышление а-ля xpath...

А что, есть еще причины, кроме тормознутости текущих реализаций? :) Конечно, интересно узнать!

Т.е. возвращаемый им массив элементов живой и в случае их удаления из ДОМ-а этот "живой" массив тоже будет меняться
Да (только это не совсем массив, это коллекция).
А что тогда происходит с querySelectorAll() в этом плане?
А он возвращает коллекцию, которая с виду очень похожа, но на последующие изменения документа не реагирует (если из документа дивы удалятся, в этой коллекции они останутся). Что-то похожее на присваивание по значению (в отличие от результата getElementsByTagName, похожего на присваивание по ссылке).
Что означает фраза ""мгновенный снимок" DOM-структуры"?

Это я так перевел слово "snapshot", которое Закас использует для неизменяемой ("неживой") коллекции, которую возвращает querySelectorAll().

Opera рулит

Кстати, да. За счет чего в Опере настолько разительно отличная от др. браузеров картина результатов бенчмарка? Вряд ли же DOM-методы в ней настолько тормознее? :)

Link to comment
Share on other sites

SelenIT,

А он возвращает коллекцию, которая с виду очень похожа, но на последующие изменения документа не реагирует (если из документа дивы удалятся, в этой коллекции они останутся). Что-то похожее на присваивание по значению (в отличие от результата getElementsByTagName, похожего на присваивание по ссылке).

Ааа, т.е. выходит, что если я удалю элемент из ДОМ-а, то обратившись потом к нему в коллекции querySelectorAll(), я просто получу допустим undefined? :unsure: Но при этом в этой коллекции он останется, да?

Или, например, я удаляю элемент из ДОМ-а, но при этом из коллекции он всё равно НЕ удаляется?

Как именно происходит?

  • Like 1
Link to comment
Share on other sites

А что, есть еще причины, кроме тормознутости текущих реализаций? :) Конечно, интересно узнать!

xpath-мышление в большинстве своем подразумевает движение под дереву от корня к детям. Путешествие по ветвям DOM-дерева практически отсутствует.

Типичное мышление примерно такое: Для того, чтобы зайти к соседу, нужно зайти в дом, в нужный подъезд, подняться на нужный этаж и зайти в нужную дверь. Хотя можно было просто выйти на лестничную клетку и зайти к соседу. Очевидно, что проще последний вариант.

Например, я часто использую поиск определенного контейнера, в котором находится нужная мне нода, т.е. двигаюсь по дереву вверх. Казалось бы, почему не применить id, и не перескочить сразу на нужную ноду? Не всегда это удобно и не всегда это полезно.

XPath-подход сильно чувствителен к изменению структуры дерева и придется заплатить или постоянной модификацией запросов, или скоростью выполнения запросов. А создавать динамическое формирование query на лету, будет еще тем занятием, ведь для динамического запроса тоже нужно будет собирать данные, чтобы он работал быстро. Так не стоит ли вообще от него отказаться и не мучаться?

Вот на хабре статья была на эту тему

Старье. Результаты самой свежей увидеть хочется

  • Like 1
Link to comment
Share on other sites

Выложите результаты бенчмарка, мне лень ставить оперу на машину.

Вот на хабре статья была на эту тему - http://habrahabr.ru/blogs/javascript/130274/

Какие-та сомнительные тесты)

Link to comment
Share on other sites

xpath-мышление в большинстве своем подразумевает движение под дереву от корня к детям. Путешествие по ветвям DOM-дерева практически отсутствует.

Ну почему, в самом XPath-е как раз есть очень удобные оси ancestor и preceding/following-sibling именно для "хождения в гости к соседям". В CSS (и, соответственно, квериселекторах) с этим, таки да, куда хуже (плюс да тильда — и всё, кажись). Но даже этих куцых возможностей хватает, например, чтобы одним махом собрать подписи к чекнутым чекбоксам (что-то типа ".myfieldset input[type=checkbox]:checked + label"), скажем, для формирования странички подтверждения после выбора чего-то из очень большой кучи во всплывающем диалоге. Не спорю, что нынешние квериселекторы не тянут на универсальную замену DOM-методам, но во многих случаях они — очень удобное подспорье/дополнение к ним. А если добавить относительную адресацию или ограничитель контекста (в том же многострадальном jQ есть) — и задачи а-ля "найти первый инпут в ближайшем общем контейнере, имеющем класс 'active', с кликнутой ссылкой" начинают легче поддаваться (без необходимости руками писать многоэтажные циклы с проверками, пользуясь правилом "меньше кода — меньше ошибок").

Вот зависимость от текущей структуры разметки — это да, ограничение. Но, по-моему, поменять один-два селектора в случае изменения структуры всё же проще, чем выворачивать вложенный цикл наизнанку или переносить половину проверок с уровня на уровень. И можно ли полностью избавиться от этой зависимости, кроме как раздав id-ы всем без исключения "участникам шоу"?

Какие-та сомнительные тесты)

Однако, в моей Опере 11.51 (Win 7 Pro x86) главная странность этого теста подтверждается: document.querySelectorAll("#a1")[0] почти равен по скорости document.getElementById("a1"), отстает всего на 7%, а вот document.querySelector("#a1") в разы медленнее.

При этом в простом тесте querySelectorAll у меня в ней оказывается в среднем втрое-вчетверо быстрее, чем getElementsByTagName (правда, последний стабильно дает разброс аж под 40%). По итоговым цифрам расклад противоположен таковому в FF8.0b. Интересно, почему?

Link to comment
Share on other sites

Testing in Firefox 7.0.1 on Linux i686

querySelectorAll - 9,440 ±4.51%96% slower

getElementsByTagName - 430,931 ±3.12% fastest

Testing in Opera 11.52 on Linux i686

querySelectorAll - 153,094 ±1.67% fastest

getElementsByTagName - 78,617 ±1.24% 49% slower

Опера сама по себе никакая.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. See more about our Guidelines and Privacy Policy