Управління швидкістю реакції сайту
Ця проблема відома давно, і виробники намагалися з нею боротися. Microsoft запропонував атрибут defer для тега script. За допомогою цього атрибута розробник може обіцяти браузеру, що в цьому конкретному скрипті document.write не використовуватиметься. Однак підтримка його різними браузерами кульгає. В інтернеті про нього різні думки, але за моїми відчуттями гуру радять не покладатися на нього.
Ще один можливий в цій ситуації варіант - якимось чином кешувати кліки по сторінці, і після завантаження скриптів обробляти кеш.
На цьому я закінчу про відображенні сторінки. Перейдемо до ініціалізації скриптів.
Найголовніша думка, яку я хочу передати в цьому розділі, проста: при ініціалізації сторінки повинен виконуватися необхідний мінімум дій.
Необхідність можна розуміти досить широко. Для початку я приведу декілька прикладів неправильного розуміння, дам «шкідливі поради».
Найпоширеніший випадок - обробляйте побільше елементів при завантаженні. Наприклад, навісьте на всі посилання на сторінці обробник. Або пройдіться по текстовим вузлів, і застосуєте до кожного типографіку. З першим нерозривно пов'язаний другий: збільшуйте кількість reflow для сторінки всіма засобами. Доречно буде динамічно поставити після кожної посилання іконку, як це робить сервіс SnapShots.com. Ще один приклад: створити про запас dom-об'єкти, які можуть стати в нагоді. Потім, при необхідності, вони будуть просто показані, і ваш код буде гладким і шовковистим.
А тепер серйозно розглянемо джерела звичайних проблем з продуктивністю при завантаженні сторінки. Найнеприємніше, з чим мені доводилося стикатися на цьому етапі - це підключення оброблювачів. У класичному варіанті це дія передбачає отримання списку елементів, події яких будуть оброблятися, і навішування на них обробників. Навіть в цьому простому алгоритмі є два місця, які можна серйозно поліпшити: це швидкість пошуку потрібних елементів і швидкість їх обробки.
Майже півтора року тому з'явилася маленька бібліотека, скоріше навіть розширення prototype.js, під назвою behavior.js. Вона дозволяла використовувати кілька розширені css-селектори для призначення обробників елементам. Тобто, робила майже те ж саме, для чого зараз часто використовується jQuery. Ідея була дуже цікава і зручна. Однак, незважаючи на всю красу, ця бібліотека практично не підходила для використання. Основна проблема була, як завжди, з всенародно улюбленим браузером: під час завантаження кожної сторінки він на кілька секунд практично підвішував комп'ютер. Корінь зла йшов в пошук елементів.
Цей варіант - використання глобальних обробників. Нагадаю, що більшість подій «спливає» вгору по дереву dom до самого кореневого елемента. Саме там їх можна виявити і обробити, використовуючи властивості подій target і srcElement для виявлення джерела події.
Які плюси нам дає цей підхід? По-перше, ми позбавляємося від необхідності шукати елементи, щоб прикріпити до них обробники подій, тому що document у нас завжди під рукою в глобальному об'єкті. Крім того, ми обробляємо тільки один елемент, а не десятки. Ще один плюс, який рідко, але дуже приємно проявляє себе - це автоматична обробка навіть динамічно створених елементів. Уявіть, як доводилося б діяти без використання цього підходу: кожен метод, який створює елементи, мав би знати обробники, які можуть бути навішені на цей елемент або використовувати складні архітектурні рішення. У разі ж глобального обробника все відбувається автомагіческі.
Так, до мінусів підходу можна віднести те, що на кожну дію користувача виконується більше операцій. Іншими словами, навантаження на процесор переноситься з ініціалізації сторінки на кліки і руху миші. Для вашого проекту це може бути невідповідним рішенням, але я вважаю, що воно найкраще в більшості випадків.
Використовуючи таку тактику, ми добиваємося того, що при завантаженні сторінки відбувається дійсно мінімум дій: на document навішується кілька обробників, і все.
Теоретично, можна поліпшити behavior.js або jQuery таким чином, щоб вони використовували саме глобальні обробники, але поки що я не знаю про такі проекти.
На цьому розмова про ініціалізації можна закінчити, і перейти до швидкості реакції елементів сторінки. Найбільш поширені події для обробки - це hover і click. Почнемо з click.
Є дуже простий спосіб прискорити реакцію на click на 100-200 мілісекунд. Для цього досить використовувати замість події click подія mousedown. Але, як завжди, виграючи час, ми програємо щось інше. В даному випадку ми жертвуємо можливістю для просунутих користувачів змінити рішення вже після натискання кнопки - в разі використання click вони могли б відвести миша в сторону. Вам вирішувати, чи готові ви на цій піти заради швидкості.
Уявіть, що у вас на сторінці є вертикальне меню, що випадає, побудоване на css-hover, і ви випадково проводите над ним мишею, ведучи її до кнопки «назад». Всі пункти меню спрацьовують по черзі, і різні підміню дуже помітно миготять на сторінці. Це відволікає, і це погано. Інший недолік теж можна проілюструвати випадає меню. Він виникає через те, що точність дій людини невелика. І саме технологія повинна вирішити цю проблему.
Отже, ось примітивний приклад меню. Я хочу заново відкрити нещодавно створений документ. Після того, як я навів миша на пункт «Останні» і побачив підміню, найприроднішим рухом для мене буде повісті курсор миші прямо до мети. Звичайно, в найпростішої реалізації у мене це не вийде як тільки курсор виявиться над пунктом «Вихід», підміню зникне. «Правильний» підхід в такому випадку - провести миша по горизонталі до субменю, і тільки потім рухати його вниз. Поскільки ширина основного меню може бути великий, а висота рядка маленької, це завдання не з простих.
Я визначив у dom-об'єктів метод delayedHover (). Усередині себе він використовує більш загальний метод функцій getDelayedHandlers (). який також визначив я. Спочатку розглянемо більш простий delayedHover (). Він отримує три параметри: власне dom-об'єкт, функцію-обробник і налаштування затримок. Усередині нього дійсно всього кілька рядків: ми викликаємо getDelayedHandlers () у функції-обробника, і призначаємо отримані з нього методи dom-об'єкту на mouseover / mouseout. Ці методи блокують спрацьовування один одного. Наприклад, якщо відразу після mouseover відбудеться mouseout, то обробник mouseover не виконається. І навпаки.
Розглянемо, як домогтися такої поведінки. Метод getDelayedHandlers () оголошує дві симетричних функції. Кожна з них спочатку скидає таймаут інший, і після цього створює свій таймаут. За таймаут основна функція викликається з параметром або true, або false.
А тепер - приклад використання «повільного hover». Нам потрібно показувати підказку для якогось елементу. Визначимо функцію, яка в залежності від параметра або показує, або ховає підказку. Після цього викличемо у кнопки метод delayedHover. і передамо йому параметрами цю функцію і временни.е настройки. Тепер підказка з'являтиметься із затримкою 200 мс, і зникати з затримкою 100 мс.