\Bitrix\Main\Page\Frame::getInstance()->startDynamicWithID("area"); //динамический контент вне компонента \Bitrix\Main\Page\Frame::getInstance()->finishDynamicWithID("area", "Загрузка..."); |
$frame = new \Bitrix\Main\Page\FrameHelper("my_dynamic_area"); $frame->begin(); //динамический контент $frame->beginStub(); //заглушка $frame->end(); |
2. Как отменить композитное кеширование в любом месте страницы (проголосовать "против") ?
\Bitrix\Main\Data\StaticHtmlCache::getInstance()->markNonCacheable(); |
3. Страницы с расширением *.html не обрабатываются. Что делать?
На странице настроек в поле "Маска включения" добавляем "*.html".
4. Как учитывать композитные страницы в Google Analytics?
Google Analytics и Яндекс.Метрика собирают данные клиентской загрузки на основе
По глобальной JS-переменной window.frameRequestStart можно определить, что страница отдалась пользователю из композитного кеша.
var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-18655900-1']); _gaq.push(['_setCustomVar', 1, 'Cache', window.frameRequestStart ? 'Composite': 'NoComposite', 3]); |
5. В чем разница между $this->createFrame()->begin(); и $this->createFrame()->begin(""); ?
Есть несколько способов выделить в шаблоне компонента динамическую область.
Самый популярный вариант выглядит так:
$frame = $this->createFrame()->begin(); //динамический контент $frame->beginStub(); //заглушка $frame->end(); |
$frame = $this->createFrame()->begin("Загрузка..."); //динамический контент $frame->end(); |
$frame = $this->createFrame()->begin(""); //динамический контент $frame->end(); |
$frame = $this->createFrame()->begin(); //динамический контент = заглушка $frame->end(); |
Этот способ позволяет избежать дублирования и повторного выполнения код.
С версии main 14.5.2 контент заглушки стал учитываться при подсчете хеш-суммы кеша.
6. Какие еще особенности у begin и beginStub?
Важно понимать, что код между вызовами begin-beginStub и beginStub-end выполняется всегда. И на первом хите к странице (на котором создается кеш) и на аякс-хите. Эти методы занимаются буферизацией контента и не являются аналогами конструкции if-else.
7. В теге <head> есть блок php, который проверяет специальный Cookie, и если он установлен, добавляет блок <style> с нужными стилями. Генерируется новая страничка, кеш перезаписывается. Как быть в таких случаях?
Вынести эту логику в Javascript.
<head> <script> if (document.cookie.indexOf("my_cookie=yes") >= 0) { //Устанавливаем класс для тега <html> document.documentElement.className += " has-cookie"; } </script> </head> <style> .block { display: none; } .has-cookie .block { display: block; } </style> |
8. Что является причиной перезаписи кеша?
Причин много. Вот самые популярные:
- Случайные ID в HTML и Javascript. Метод randString поможет решить эту проблему.
- Вывод данных из сессии (id, login).
- Контент страницы зависит от User Agent.
- Разный контент для анонимного и для авторизованного пользователя.
- Добавление на страницу CSS- и JS-файлов в зависимости от пользователя.
9. Поменяли верстку в шаблоне сайта, но страницы из кеша отдаются в старом дизайне.
Кеш обновляется фоновым аякс-запросом, поэтому первый хит будет еще со старым дизайном.
После подобных изменений сайта эффективнее очистить весь композитный кеш.
10. Счетчик товаров в корзине пользователя находится в динамической области. Некрасиво прыгает цифра: сначала ноль, потом один.
Давайте подобно посмотрим, из-за чего это происходит.
- В файл кеша записывается заглушка "0 товаров в корзине".
- Страница из кеша отдается пользователю и показывается.
- Даже если аяксовый хит с нужными данными приходит раньше, чем отрендерилась страница, все равно пользователь на мгновение видит заглушку.
- Это происходит из-за того, что все вставки в innerHTML (в том числе из sqlite) происходят на событии DOMContentLoaded.
- Хотя в большинстве случае виноват даже не DOMContentLoaded, а долгое выполнение аяксового запроса.
Чтобы побороть моргание, нужно вставить актуальные данные в страницу до того, как она покажется пользователю.
Как вставить до рендеринга?
а) document.write - это конструкция останавливает рендеринг страницы, для того, чтобы на лету вставить в DOM новый HTML. Разработчики браузеров не рекомендуют ее использовать, но она работает.
б) Разместить Javascript в странице так, чтобы он располагался после HTML'я, к которому обращается.
Это старый забытый способ начала 2000-x годов, когда еще jQuery'ая $.ready() не замылила всем глаза.
$.ready() или битриксовая BX.ready - это выполнение кода на событии DOMContentLoaded. Это событие гарантирует, что DOM построен и к нему можно безопасно обращаться. Минус этого события в том, что на больших страницах интерфейс уже успевает пользователю показаться, отсюда и моргание.
<!doctype html> <html> <body> <div id="box" style="width: 100px; height: 100px; background: red;"></div> <script>document.getElementById("box").style.background = "blue";</script> <table><tr><td>some html below</td></tr></table> </body> </html> |
Да, есть вероятность нарваться на Exception, поэтому можно подстраховаться:
function changeBox() { document.getElementById("box").style.background = "blue"; } var box = document.getElementById("box"); if (box) { changeBox(); } else { BX.ready(function() { changeBox(); }); } |
Откуда взять актуальные данные?
Три варианта:
- Cookies
- SQLite
- LocalStorage
Самый приемлемый вариант - это localStorage. Это key-value хранилище, которое поддерживается всеми браузерами, даже IE8.
Данные localStorage доступны мгновенно сразу во всех вкладках. Т.е. если у пользователя открыто 10 вкладок магазина и он в одной из них жмет "Добавить в корзину", то через событие localStorage'а можно мгновенно поменять во всех вкладках счетчик корзины.
Для localStorage в Битриксе есть своя обвязка под названием BX.localStorage. Она позволяет указывать время хранения данных.
Основные методы:
BX.localStorage.set(key, value, ttl)
BX.localStorage.get(key)
BX.localStorage.remove(key)
События:
BX.addCustomEvent("onLocalStorageSet", function(data) { console.log(data.key, data.value) });
BX.addCustomEvent("onLocalStorageRemove", function(data) {});
BX.addCustomEvent("onLocalStorageChange", function(data) {});
В итоге: счетчик корзины и имя пользователя можно кешировать в localStorage и использовать эти данные для борьбы с морганием.
11. Если еще какие-нибудь способы борьбы с морганием?
Все зависит от дизайна сайта и от контента динамических областей.
Старайтесь делать верстку так, чтобы вставка динамических областей не приводила к прыганию соседних элементов.
C помощью метода setAnimation(true) можно добавить эффект плавного появления контента.
Экспериментируйте с содержимым заглушек. Заглушка может быть пустой, а может повторять содержимое динамической области (см. пункт 5).
12. Динамическая область автоматически оборачивает свой контент в дополнительный div, который портит верстку сайта.
Композитному кешированию необходимы html-контейнеры для вставки в них содержимого динамических областей.
Можно использовать свои контейнеры:
echo '<div id="my_div">'; $frame = $this->createFrame("my_div", false)->begin(); //динамический контент $frame->beginStub(); //заглушка $frame->end(); echo '</div>'; |