Разгони свой сайт Лекция 8: Быстрый JavaScript Мациевский Николай webo.in 1 / 24 Содержание • • • • • Замыкания и утечки памяти «Тяжелые» JavaScript-вычисления Быстрый DOM Кэширование в JavaScript Элементарные операции webo.in 2 / 24 Замыкания и утечки памяти webo.in 3 / 24 Шаблоны утечек • • • • Циклические ссылки Замыкания Постраничные утечки Псевдо-утечки webo.in 4 / 24 Циклические ссылки • Объект из области JavaScript создает ссылка на DOM-узел • DOM-узел создает ссылку на другой объект JavaScript • Сборка мусора • Объект JavaScript ждет DOM-узел • DOM-узел ждет другой объект JavaScript webo.in 5 / 24 Замыкания • JavaScript объект создает замыкание • DOM-узел обращается к этому замыканию • JavaScript снимает ссылку с замыкания • Замыкание живет, поскольку нужно DOM-узлу • Сборщик мусора не отслеживает такие ссылки webo.in 6 / 24 Постраничные утечки • Порядок добавления элементов в DOM-дерево играет значение • Промежуточные узлы создают «миниутечки» • Добавление узлов непосредственно к текущему дереву не «течет» webo.in 7 / 24 Псевдо-утечки • Выделение памяти для кэша DOM-узлов • Выделение памяти для глобальных объектов • Выделение памяти под замыкания • Все это не утечки, а особенности функционирования JavaScript webo.in 8 / 24 «Тяжелые» JavaScript-вычисления webo.in 9 / 24 Ограничение на выполнение • Есть предел выполнения JavaScript • Время выполнения (Mozilla) • Число элементарных операций (IE) • Выделяемая память (Firefox) • Мобильные агенты гораздо «слабее» настольных компьютеров webo.in 10 / 24 Обратная связь • Рекурсивное выполнение • arguments.callee • + setTimeout( , 0) • Браузер останавливает поток и проверяет состояние • Получаем интерактивное выполнение webo.in 11 / 24 Улучшаем шаблон • Интерактивность и накладные расходы • Группировка итераций • В setTimeout не строка, а вызов функции • Синхронизация глобальных переменных webo.in 12 / 24 Быстрый DOM webo.in 13 / 24 DocumentFragment • Поддерживается в IE6+ • Позволяет создать фрагмент дерева • Быстрее для элементарных операций var div = document.getElementsByTagName("div"); var fragment = document.createDocumentFragment(); for ( var e = 0; e < elems.length; e++ ) { fragment.appendChild( elems[e] ); } for ( var i = 0; i < div.length; i++ ) { div[i].appendChild( fragment.cloneNode(true) ); } webo.in 14 / 24 innerHTML • innerHTML быстрее DOM-методов • Передаваемый HTML нужно фильтровать var i, j, el, idx=0, html=[]; html[idx++] = "<table>"; for (i = 0; i < 1000; i++) { html[idx++] = "<tr>"; for (j = 0; j < 5; j++) { html[idx++] = "<td></td>"; } html[idx++] = "</tr>"; } html[idx++] = "</table>"; el = document.createElement("div"); document.body.appendChild(el); el.innerHTML = html.join(""); webo.in 15 / 24 Кэширование в JavaScript webo.in 16 / 24 Необходимость кэширования • • • • Сложная клиентская логика = 50-500 мс Серверные запросы = 50-200 мс DOM-вызовы = 1-10 мс Доступ к глобальным объектам = 0.1-1 мс • Но! Большое число объектов замедляет обращение к каждому webo.in 17 / 24 Кэширование вызовов • В локальные переменные var arr = document.getElementsByTagName(‘*’); var globalVar = 0; (function () { var i, l, localVar; l = arr.length; localVar = globalVar; for (i = 0; i < l; i++) { localVar++; } globalVar = localVar; })(); webo.in 18 / 24 Кэширование DOM-узлов • В локальные переменные var arr = document.getElementsByTagName(‘*’); var globalVar = 0; (function () { var i, l, localVar; l = arr.length; localVar = globalVar; for (i = 0; i < l; i++) { localVar++; } globalVar = localVar; })(); webo.in 19 / 24 Кэширование цепочек • Такой пример for (i=0; i < 10000; i++) a.b.c.d(v); • будет выполняться медленнее, чем var f=a.b.c.d; for (i=0; i < 10000; i++) f(v); • или var f=a.b.c; for (i=0; i < 10000; i++) f.d(v); webo.in 20 / 24 Элементарные операции webo.in 21 / 24 Регулярные выражения • Классический пример var RegExp = '/script/gi'; items[i].nodeName.search(RegExp); • в полтора раза медленнее, чем /script/i.test(items[i].nodeName); • или /script/i.exec(items[i].nodeName); webo.in 23 / 24 Перебор массива • Классический пример for (var j=0; j<10000; j++) { for (var i=0; i<items.length; i++) { var item = items[i]; } } • в 2-4 раза медленнее, чем for (var j=0; j<10000; j++) { var i = length - 1; while (--i) { var item = items[i]; } } webo.in 22 / 24 В следующей лекции Практическое приложение • • • • Инструменты для анализа Онлайн-приложения Оптимизация браузеров Разбор полетов webo.in 24 / 24