Оптимизация JavaScript часть 3: Подписка на события

Это третья часть учебника по оптимизации JavaScript, и сегодня я хочу поговорить о событиях. Простите за длительный перерыв между статьями, надеюсь, оставшиеся части будут публиковаться регулярнее.

Сценарий: у вас есть элементы, и необходимо добавить какую-то функциональность к ним (например, когда пользовательно наводит мышку на элемент, или щелкает по элементам).

Это обычная задача в веб-разработке. И первая вещь, которую знает каждый,– это разный синтаксис подписки на события в Internet Explorer и Firefox: первый использует element.attachEvent, второй — element.addEventListeners. Поэтому Вам нужно добавлять проверки, какой браузер используется в каждом конкретном случае. В наиболее популярной библиотеке Prototype это уже стандартизировано, и Вы всегда можете использовать Event.observe. Давайте немного потестируем.

Я начну с подписки на события через определение браузера вручную:

// Attaching events
for (var i = items.length; i--; ) {
    if (items[i].addEventListener) {
        items[i].addEventListener('click', e_onclick, false);
    } else if (items[i].attachEvent) {
        items[i].attachEvent('onclick', e_onclick);
    }
}
// Detaching events
for (var i = items.length; i--; ) {
    if (items[i].removeEventListener) {
        items[i].removeEventListener('click', e_onclick, false);
    } else if (items[i].detachEvent) {
        items[i].detachEvent('onclick', e_onclick);
    }
}

Этот подход показал лучшее время: 188 и 203 ms в Internet Explorer 6 и 7, 125 и 141 ms в Firefox 1.5 and 2.0, и 63 ms в Opera 9, но есть одна проблема — утечки памяти: Internet Explorer обычно забывает почистить память, используемую обработчиками событий, когда Вы переходите на другую страницу. Поэтому все JavaScript-фреймворки, реализующие функции подписки/отписывания от событий, предоставляют возможность автоматического удаление обработчиков при переходе на другую страницу. Давайте потестируем их.

Код для библиотеки Prototype:

// Attaching events
for (var i = items.length; i--; ) {
    Event.observe(items[i], 'click', e_onclick, false);
}
// Detaching events
for (var i = items.length; i--; ) {
    Event.stopObserving(items[i], 'click', e_onclick, false);
}

Это очень медленно, 6453 ms в Internet Explorer 6, и похоже на то, что все еще есть какие-то утечки памяти (становится все медленнее и медленнее со временем), и 365 — 653 ms в других браузерах.

Существует множество проблем и решений с подпиской на события (взгляните только на Advanced event registration models). Не так давно даже прошло соревнование PPK’s addEvent() Recoding Contest (но не вздумайте использовать решение победителя в своих приложениях, оно крайне неэффективно и приводит к утечкам памяти).

Вместо него я решил протестировать невероятное и дерзкое решение от Dean Edwards, которое даже не использует методы addeventListener/attachEvent, но является полностью кросс-браузерным!

Использованный код:

// Attaching events
for (var i = items.length; i--; ) {
    addEvent(items[i], 'click', e_onclick);
}
// Detaching events
for (var i = items.length; i--; ) {
    removeEvent(items[i], 'click', e_onclick);
}

Результаты настолько же впечатляющие, как и при подписке на события вручную, этот подход невероятно быстр для использования в реальных приложениях. Безусловно, Вы скажете: “Стоп, о чем ты говоришь? Я не хочу использовать дополнительные методы, ведь я уже использую Prototype в своем коде!” Остыньте, Вам не нужно делать этого, просто скачайте библиотеку Low Pro (текущая версия — 0.4, не забывайте обновляться). Разработчики Ruby on Rails могут воспользоваться плагином UJS Rails Plugin в своих приложениях для улучшения производительности — он включает и оптимизации Low Pro.

No Method IE 6 IE 7 FF 1.5 FF 2.0 Opera 9
1 manually 203 188 125 141 63
2 prototype.js 6453 653 547 469 365
3 addEvent 783 344 94 141 62

Тест производительности: Подписка на события

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

Выводы

  • Всегда используйте Low Pro с Prototype.js (конечно, если Ваше приложение содержит продвинутую логику на стороне клиента).
  • Подписывайтесь на события вручную, если Вам нужно выжать максимальную скорость из Вашего приложения (например, когда Вы манипулируете сотнями элементов). Но не забывайте об утечках памяти!
  • Избегайте подписки на события везде, где это возможно (например, используйте CSS селектор :hover вместо события onmouseover).
  • Будьте начеку, возможно завтра кто-то опубликует другие подсказки по оптимизации производительности.

Ссылки на другие части

Источник: http://kpumuk.info



Опубликовал admin
10 Май, Четверг 2007г.



Программирование для чайников.