|
|||||||
Ускоряем селекторы в jQuery
Время создания: 08.12.2010 19:29
Раздел: Компьютер - Программирование - Java Script - Библиотека jQuery
Запись: xintrea/mytetra_syncro/master/base/0000003351/text.html на raw.github.com
|
|||||||
|
|||||||
Когда я вчера начинал писать эту статью я хотел написать что-то типа "селекторы для продвинутых" небольшое руководство по сложным выборкам, но как то так получилось, что я отклонился от темы в сторону обьяснения внутрених механизмов jQuery и получилось что-то средние между "селекторами для продвинутых" и "перфомансом селекторов", что тоже не плохо. Объяснять как работают селекторы я буду на простейшем примере, который лучше смотреть в FF3.1 или IE8: <style> .myClass{ color:red; } </style> <select name="myName"> <option value="101">101</option> <option value="102">102</option> <option value="103">103</option> <option value="104">104</option> <option value="105">105</option> <option value="106" class="myClass">106</option> <option value="107" class="myClass">107</option> <option value="108" disabled="disabled">108</option> <option value="109" disabled="disabled">109</option> <option value="110" disabled="disabled" class="myClass">110</option> </select> Теперь напишем селектор который выберет все элементы которые нам видны, которые имеют класс myClass и которые неактивны. jQuery().ready(function($){ // выбираем все option var o = $("select[name=myName] option"); // фильтруем o.filter(":visible.myClass:disabled"); }); Работает, но это не оптимальный селектор, даже если он занимает минимум символов при написании, он работает медленно. Надо понимать как это все работает и какая операция быстрее. Итак попробуем разобрать: если бы все было прекрасно и браузер поддерживал функцию document.querySelectorAll, jQuery бы передал ей селектор, но у нас не та ситуация, я спецально создал такие условия чтобы querySelectorAll ничего не ускорил, ну или мы используем какойто старый браузер который не поддерживает этот метод. Итак у нас три части селесктора :visible + .myClass + :disabled , (и хотя querySelectorAll понимает второй селектор, jQuery всеравно придеться обрабатывать первый и третий) примерный код выглядел бы так, только намного сложнее. // Этот код работает идентично тому как работает jQuery // выбираем все option без jQuery var o = document.querySelectorAll("select[name=myName] option"), tmp1 = [], tmp2 = [], result = []; function isVisible(obj){ if (obj == document) return true; if(!obj) return false; if(obj.style.display !== "none" && obj.style.visibility !== "hidden") return isVisible(obj.parentNode); } // фильтруем for (var i=0; i<o.length; i++){ if(isVisible(o[i])) tmp1.push(o[i]); } // 10 for (var i=0; i<tmp1.length; i++){ var cls = tmp1[i].className.split('/\s+/') for (var c in cls) if (cls[c] == "myClass") tmp2.push(tmp1[i]); } // 3 for (var i=0; i<tmp2.length; i++){ if(tmp2[i].getAttribute("disabled")) result.push(tmp2[i]); } // 1 alert(result.length); // 1 Конечно есть механизмы оптимизации, но есть и много другого кода поэтому от него отстранимся и будем решать нашу задачу. Задача очень простая надо посчитать общее количество циклов и трудозатраты на каждом цыкле. Конечно есть механизмы оптимизации, но есть и много другого кода поэтому от него отстранимся и будем решать нашу задачу. Задача очень простая надо посчитать общее количество циклов и трудозатраты на каждом цикле. Итак, считаем:
Посчитаем общую сложность 10*3+10*2+3*1=53. Попробуем поменять местами поставив самые простые на перед - 10*1+3*2+1*3=19, получается в 2,5 раза меньше. Отсюда вывод, что в примере селекторы лучше всего поменять местами в противоположном порядке - :disabled.myClass:visible. Конечно пример про :visible натянут тут они все видимы но в реальной ситуации когда выбираются все абзацы текста, все может быть по другомую. В общем это я все клоню к тому, что для того чтобы селекторы быстро работали надо вначале писать самые простые, отсекающие как можно больше элементов, а потом сложные чтобы они фильтровали как можно меньше элементов. 21.02 UPD: Несколько часов назад вышла jquery-1.3.2.js . В release note сказано что отремонтированы селекторы :visible/:hidden и действительно сейчас они полностью переписаны и не зависят от величины дом дерева. vae element = document.getElementById("id") if(!element.offsetWidth && !elem.offsetHeight) // hidden else // visible А это значит про предыдущие расчеты нужно немного подкорректировать и теперь самым 'тяжелым' является селектор класса. |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|