Настройка ретаргетинга facebook. IV

Сейчас я расскажу Вам об интересном способе, который поможет вам ускорить свой сайт на WordPress за счет параллельной загрузки скриптов.

Для чего это нужно?

Все очень просто. Современный сайт представляет из себя сборник самых разнообразных скриптов, тегов, сниппетов, стилей, шрифтов и всего прочего. Как вы понимаете, чем больше «плюшек», тем дольше грузится ваш сайт. Что касается JavaScript, тут отдельная песня. Замечали ли вы такой косяк, когда страница вроде бы загрузилась, но вкладка показывает, что страница все еще грузится? Так бывает, когда какой-то отдельный скрипт не прогрузился до конца. Ладно бы так, иногда страница вообще простаивает до тех пор, пока не загрузится тот самый, вроде бы и не совсем важный скрипт. А у ваших пользователей просто может не хватить терпения.

Данное понятие полностью противоположно синхронной загрузке, коей является обычный скрипт вида:

Асинхронный вызов скрипта выглядит так:

Теперь скрипты не будут заставлять ваших пользователей ждать своей полной загрузки, все будет проходить параллельно.

Как автоматизировать процесс?

Понятное дело, если скрипты вы подключаете вручную и их не много, то сделать это можно и ручками, просто дописав соответствующий атрибут к коду вызова. Но как это дело автоматизировать, если, например, у вас WordPress с кучей скриптов, которые, вдобавок, вызываются автоматически?

Находим уже знакомый нам файл functions.php вашей темы и вставляем туда (например в конец) следующий код:

// асинхронный javascript function wcs_defer_javascripts ($url) { if (FALSE === strpos($url, ".js")) return $url; if (strpos($url, "jquery.js")) return $url; return "$url" async="async"; } add_filter("clean_url", "wcs_defer_javascripts", 11, 1);

Заключение

Что можно добавить в заключение. Данный скрипт, возможно, подойдет не всем, так-как, кто его знает, какие скрипты подключены именно у вас, поэтому, ставьте и экспериментируйте. Минуса у такого скрипта быть не может, разве что несовместимость с конкретным сайтом ввиду его специфики. Это был еще один маленький шаг по большой оптимизации вашего сайта.

Иногда возникает необходимость в поэтапной асинхронной загрузке данных. И это может быть все, что угодно. Начиная от загрузки зависимых справочников (например, страна -> города), заканчивая объединением и обработкой информации с различных источников (например, вы используете несколько разных сервисов, и каждый из них тратит разное время на формирование данных).

А теперь чуть попроще.

Проблематика поэтапной асинхронной загрузки данных в jQuery (ajax)

Если вам надо связать несколько последовательно выполняемых ajax-запросов в jQuery, то самым простым решением будет - сделать вызов следующей функции в конце каждого обработчика success. Это не только достаточно просто, но и не вызывает никаких проблем. Например,

// Первый запрос $.ajax(url, { ... success: function (result) { // Какой то код... // Вызов следующего обработчика nextLoader(); } });

А теперь, допустим, перед вами стоит чуть более сложная задача. Например, вам необходимо запустить функцию только после того, как выполнятся несколько асинхронных запросов (например, получение пузомерок для сайта). Конечно, их так же можно связать в прямую цепочку, как это было показано выше. Но, при этом начинает теряться сама суть асинхронности. И так же может получиться, что вы строите зависимость между совершенно не связанными блоками. Согласитесь, что показатель тИЦ и данные по whois не совсем зависят друг от друга.

Тем не менее, не смотря на все тонкости, решить такую задачу можно достаточно быстро, пусть и немного топорным методом.

Но, что вы будете делать, если ваша задаче окажется еще сложнее? Когда вам необходимо все операции и загрузки данных распределить по этапам. Например, вы составляете формочку диалога. На первом этапе будет идти получение данных для всех полей (выпадающие списки, группы чекбоксов и т.д.). На втором этапе будет происходить определение обработчиков для созданных полей. А на третьем этапе, уже после полной загрузки "всё и вся", открывать доступ к различным кнопкам и другим элементам интерфейса (чтобы шаловливые ручки не создали вам кучи проблем). Чисто визуально это может выглядеть так:

Согласитесь, что организовать вызов всех функций в одну цепочку - ни только не простое занятие, но еще и не очень приятное. Кроме этого еще представьте, что вам надо добавить несколько полей и различных обработчиков. Что будет? У вас начнет голова закипать от поиска нужных мест "куда вставить". Тут уже нужен какой-то механизм, который позволит вам выстроить все запуски поэтапно.

Пишем скрипт для организации поэтапной асинхронной загрузки в jQuery

Первым делом необходимо определиться с вполне логичным вопросом "почему не использовать готовые библиотеки?". Как такового, ответа на этот вопрос не существует. Все очень сильно зависит от задачи. Так как слово "библиотека" обычно подразумевает:

  • отсутствие управляемости кода (вы не можете поменять внутреннюю логику библиотеки; а если вы это сделаете, то любое изменение может сильно "аукнуться" в будущем)
  • необходимость изучения ее базовый свойств и принципов (обычно, это сводится к прочтению всей возможной документации и куче различных тестов)
  • ограничения на версии jQuery (если используются сложные ядровые механизмы, то возможно привязка к версии библиотек jQuery)
  • возможные проблемы совместимости с другими скриптами (далеко не факт, что библиотека будет корректно себя вести с другими библиотеками)
  • чрезмерное богатство функциональности, и как следствие наличие "дополнительных ограничений"
  • и т.д.

Примечание : Не стоит входить в заблуждение, ведь у библиотек есть огромное количество плюсов. Если вспомнить, то и jQuery - это то же библиотека. В статье акцент фокусируется на рисках и дополнительных затратах времени, которые от вас могут потребоваться.

Именно, поэтому необходимо сначала определиться с вашими задачами (количество, частота возникновения), со временем (сколько вы готовы потратить на решение задачи), чем вы готовы пожертвовать (важна ли для вас возможность быстро что-то подправить; важен ли размер библиотек; насколько ограничения вас устраивают), предпочтениями (например, вы принципиально не используете библиотеки). И уже только после того, как вы ответите себе на эти вопросы, пытаться ответить на вопрос "почему стоит или не стоит использовать готовые библиотеки?".

Если вы ответили себе, что хотите использовать библиотеки, то, как вариант, можете скачать уже готовый тестовый пример с готовым скриптом в конце статьи.

Если же вы полны энтузиазма и решимости, то преступим к дальнейшим действиям.

Составляем требования к скрипту

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

  • Подключение и настройка скрипта должны происходить автоматически (вам необходимо подключить лишь файл js)
  • Повторное подключение файла скрипта не должно вызывать сбой
  • Использовать только стандартные механизмы jQuery
  • Интерфейс должен быть простым и понятным
  • Вы можете составлять несколько независимых цепочек этапов
  • У вас всегда должна быть возможность быстро подкорректировать действия скрипта
  • Скрипт не должен накладывать сложные ограничения на ваш код (максимально - необходимость в добавлении функции оповещения о своем выполнении)

Примечание : Всегда формируйте требования так, чтобы при реализации не начать заниматься тем, что вообще не требуется. И обязательно включайте в него "итак понятные" пункты, чтобы эти пункты и дальше оставались "итак понятными".

Составляем тестовый проект

Структура проекта будет выглядеть следующим образом:

  • css - каталог со стилями
    • template.css - стили тестового проекта
  • images - каталог с картинками (для визуального эффекта)
    • ajax-loader.gif - картинка загрузки
  • js - каталог со скриптами
    • jquery-ajax-stage.js - скрипт для поэтапной загрузки
  • data.json - тестовые данные
  • index.html - начальная страница

Примечание : При составлении структуры тестового проекта, старайтесь максимально приблизить ее к структуре настоящего проекта. Это поможет вам отловить проблемы, связанные со структурой, еще на этапе разработке.

Файл с тестовыми данными - data.json

Этот файл нужен только для того, чтобы можно было убедиться, что загрузка данных через ajax никак не повлияет. Вы можете наполнить его любым json. Например, так:

{ data: "Много данных" }

Примечание : Старайтесь делать так, чтобы тестовые примеры были максимально схожи с реальными. Пусть даже вызовы функций будут бессмысленными.

Файл стилей - template.css

Этот файл нужен только затем, чтобы вынести все стили отдельно. Так как к самой разработке скрипта стили не имеют никакого отношения. Да, и просто это считается хорошей практикой. Сами стили:

Left-table { float: left; padding-right: 10px; } .right-table { float: left; padding-right: 10px; } table.table-loader { border-spacing: 0px; border-collapse: collapse; width: 300px; } table.table-loader tr td { padding: 5px; border: 1px solid #ccc; }

Файл скрипта для поэтапной асинхронной загрузки - jquery-ajax-stage.js

Сама реализация поэтапной асинхронной загрузки.

(function (parentObject) { // Защита от повторного определения if(parentObject.eventManager) return; // Определяем объект parentObject.eventManager = { // Добавляем этап addStage: function (el, stageName) { var elCount = $(el).length; // Проверяем корректность параметров if(elCount > 0 && !!stageName) { // Такой этап уже есть if (($(el).get(0).eventStages = $(el).get(0).eventStages || {})) return; // Определяем "nfg $(el).get(0).eventStages = { waiterCount: 0, // Счетчик объектов находящихся в состоянии ожидания данных onEvent: // в данном массиве будут хранится все функции для вызова }; } }, // Удаляем этап removeStage: function (el, stageName) { var elCount = $(el).length; // Проверяем корректность параметров if(elCount > 0 && !!stageName) { // Такой этап нашелся if (($(el).get(0).eventStages = $(el).get(0).eventStages || {})) { delete ($(el).get(0).eventStages = $(el).get(0).eventStages || {}); ($(el).get(0).eventStages = $(el).get(0).eventStages || {}) = null; } } }, // Увеличиваем счетчик выполняемых функций для этапа addStageWaiter: function (el, stageName) { var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el).get(0).eventStages || {}); // Проверяем корректность параметров if(elCount > 0 && !!stageName && stage) { // Увеличиваем счетчик загрузок stage.waiterCount++; } }, // Уменьшаем счетчик выполняемых функций для этапа // Т.е. оповещаем, что функция выполнилась removeStageWaiter: function (el, stageName) { var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el).get(0).eventStages || {}); // Проверяем корректность параметров if(elCount > 0 && !!stageName && stage) { // Уменьшаем счетчик загрузок stage.waiterCount--; // Проверяем состояние этапа this.checkStage(el, stageName); } }, // Проверяем состояние этапа checkStage: function (el, stageName) { var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el).get(0).eventStages || {}); // Проверяем корректность параметров if(elCount > 0 && !!stageName && stage) { if (stage.waiterCount 0) { // Очередь FIFO - первый вошел, первым вышел, как в магазине stage.onEvent.shift()(); } } } }, // Добавляем вызов функции, который запустится при выполнении всего этапа onLoadStage: function (el, stageName, funcHandler) { var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el).get(0).eventStages || {}); // Проверяем корректность параметров if(elCount > 0 && !!stageName && stage && typeof (funcHandler) === "function") { // Добавляем обработчик stage.onEvent.push(funcHandler); // Проверяем состояние этапа this.checkStage(el, stageName); } } }; })(window);

Тестовая страница - index.html

Тестовая страница получилась достаточно большой (порядка 160 строк), поэтому будет приведена только часть кода. Полную версию файла вы всегда можете найти в zip-архиве.

Подключаем все необходимые файлы:

Составляем пару тестовых блоков. В блок входит кнопка для запуска и таблица куда поэтапно будут записываться данные.

Начать загрузку

Определим функцию, которая будет создавать тестовые функции для этапов:

function getFakeLoader(storage, currStage, startDate, selector) { return function () { setTimeout(function () { $.ajax("data.json?callback=?", { contentType: "text/plain; charset=utf-8", dataType: "jsonp", jsonpCallback: function (result) { $(selector).html("Время от начала: " + ((+new Date() - startDate)/1000.0).toFixed(2) + " секунд"); // Пишем время загрузки window.eventManager.removeStageWaiter(storage, currStage); // Уменьшаем счетчик } }); }, Math.random() * (3000) + 1000 // Задежрка от 1 до 4 секунд); }; }

Создаем функцию, которая будет описывать логику для каждого тестового блока:

function formTestFor(selector) { $(selector + " .start-process").click(function () { var startDate = new Date(); // Для красоты добавим картинки setLoaderImgs(selector); // Определим этапы window.eventManager.addStage($(selector + " .table-loader"), "1"); window.eventManager.addStage($(selector + " .table-loader"), "2"); window.eventManager.addStage($(selector + " .table-loader"), "3"); // Заблокируем кнопку до конца этапа $(selector + " .start-process").attr("disabled", "disabled"); // Наполним очередь ожидания по 3 загрузки на стейдж // По факту эти действия должны происходить в местах запуска функций этапов window.eventManager.addStageWaiter($(selector + " .table-loader"), "1"); ... window.eventManager.addStageWaiter($(selector + " .table-loader"), "3"); // Теперь создадим в обратном порядке (для наглядности) функции загрузки // По факту эти действия должны происходить в местах определения функций window.eventManager.onLoadStage($(selector + " .table-loader"), "2", getFakeLoader($(selector + " .table-loader"), "3", startDate, selector + " .row-3 .td-1")); ... window.eventManager.onLoadStage($(selector + " .table-loader"), "1", getFakeLoader($(selector + " .table-loader"), "2", startDate, selector + " .row-2 .td-3")); // Добавим обычный текстовый вывод готовых этапов window.eventManager.onLoadStage($(selector + " .table-loader"), "1", function () { $(selector + " .row-1-end td").html("Первый этап закочнился за " + ((+new Date() - startDate)/1000.0).toFixed(2) + " секунд. Начинается следующий этап."); }); ... window.eventManager.onLoadStage($(selector + " .table-loader"), "3", function () { $(selector + " .row-3-end td").html("Третий этап закочнился за " + ((+new Date() - startDate)/1000.0).toFixed(2) + " секунд.
Загрузка окончена"); }); // После окончания третьего этапа разблокируем кнопку onLoadStage window.eventManager.onLoadStage($(selector + " .table-loader"), "3", function () { // Разблокируем кнопку $(selector + " .start-process").attr("disabled", null); }); // Теперь запустим функции первого этапа getFakeLoader($(selector + " .table-loader"), "1", startDate, selector + " .row-1 .td-1")(); getFakeLoader($(selector + " .table-loader"), "1", startDate, selector + " .row-1 .td-2")(); getFakeLoader($(selector + " .table-loader"), "1", startDate, selector + " .row-1 .td-3")(); // Наблюдаем... }); }

Теперь собираем все файлы в проект и переходим к первичному тестированию и демонстрации.

Смотрим результат

Открываем файл index.html в браузере. Должен отобразиться следующий интерфейс:

Как видно, нам доступно две кнопки для запуска параллельных процессов. После нажатия на них, должна начаться загрузка для соответствующих блоков. И выглядеть это будет примерно так:

После того, как оба процесса закончили свое выполнение, смотрим на время и убеждаемся, что этапы происходили в нужном порядке:

Закончив первичное тестирование, переходим к проверке требований:

  • Подключение и настройка скрипта должны происходить автоматически (вам необходимо подключить лишь файл js) - Есть
  • Повторное подключение файла скрипта не должно вызывать сбой - Есть
  • Использовать только стандартные механизмы jQuery - Есть (использовался только функционал селекторов)
  • Интерфейс должен быть простым и понятным - Есть
  • Вы можете составлять несколько независимых цепочек этапов - Есть
  • У вас всегда должна быть возможность быстро подкорректировать действия скрипта - Есть (скрипт составлен достаточно просто; основную часть составляют проверки входных данных)
  • Скрипт не должен накладывать сложные ограничения на ваш код (максимально - необходимость в добавлении функции оповещения о своем выполнении) - Есть (внутри функций getFakeLoader вызывается только функция для оповещения о своем завершении)

Теперь у вас есть простой и понятный скрипт, который поможет вам быстро организовать поэтапное выполнение функций, будь то загрузка данных или просто выполнение операций.

Примечание: ниже расположен перевод статьи от Steve Souders (автора знаменитых советов Yahoo! касательно клиентской производительности) "Coupling async scripts" . Steve анализирует поведение JavaScript-файлов при загрузке и предлагает несколько путей для обхода их «блокирующих» свойств. Мои комментарии далее курсивом.

Большая часть моей работы в последнее время была посвящена асинхронной загрузке внешних скриптов . Если скрипты загружаются в обычном порядке (), то они блокируют загрузку всех остальных компонентов страницы (в последних версиях Firefox и в Safari это не так, но речь идет, в основном, про 70% пользователей с IE ) и блокируют отрисовку всей той части страницы, которая расположена ниже вызова скриптов по HTML-коду. Это можно увидеть на тестовой странице размещаем скрипты внизунапример, при помощи динамического создания объектов после срабатывания комбинированного события window.onload ) предотвращает такое поведение браузера, что ускоряет загрузку страницы.

Единственная проблема с асинхронной загрузкой скриптов заключается в их взаимодействии с внутренними (inline ) скриптами страницы (а также с другими внешними скриптами ), которые используют переменные, определенные во внешнем скрипте. Если внешний скрипт загружается асинхронно безо всякого представления о внутреннем коде HTML-страницы, то вполне возможна ситуация (и она будет возникать в большинстве случаев ), когда некоторые переменные будут не определены на момент их использования. Поэтому необходимо убедиться, что внешние скрипты, загруженные асинхронным образом, и внутренние скрипты страницы состыкованы: внутренние скрипты не выполняются до тех пор, пока асинхронные скрипты полностью не загрузятся.

Существует несколько (стандартных ) путей для стыковки асинхронно загружаемых скриптов с другим JavaScript-кодом:

  • window onload . Выполнение внутреннего JavaScript-кода может быть привязано к событию window onload . Это очень просто в использовании, но часть скриптов может быть выполнена раньше.
  • onreadystatechange у скрипта . Внутренний код может быть привязан к событию onreadystatechange и(ли) onload . (Необходимо будет использовать оба варианта, чтобы покрыть все популярные браузеры.) В этом случае кода будет больше, он будет более сложным, но будет гарантия, что он исполнится сразу после загрузки соответствующих внешних файлов.
  • Встроенные вызовы . Внешние скрипты могут быть модифицированы таким образом, чтобы включать в самом конце вызов небольшого участка кода, который вызовет соответствующую функцию из внутреннего кода. Это все замечательно, если внешние и внутренние скрипты разрабатываются одной и той же командой. Но в случае использования сторонних разработок, это не обеспечит всей необходимой гибкости для связки внешних скриптов с внутренним кодом.

В этой заметке я параллельно (никакого каламбура!) освещаю два вопроса: как асинхронные скрипты ускоряют загрузку страницы и как можно состыковать асинхронные скрипты и внутренние используя модифицированный вариант загрузчика от John Resig (автора jQuery ) — шаблон двойного тэга script . В качестве иллюстрации этого можно привести мою недавнюю работу по сортировке результатов UA Profiler . Я выполнил ее при помощи скрипта сортировочного скрипта от Stuart Langridge. Примерно за 5 минут я смог добавить его скрипт на страницу для сортировки таблицы с результатами. Затратив немного больше времени, я смог сделать загрузку этого скрипта асинхронной и ускорить загрузку страницы более чем на 30%, используя технику стыковки асинхронных скриптов.

Обычные вызовы скриптов

Изначально я добавил сортирующий скрипт Stuart Langridge на страницу UA Profiler обычным способом (через ), это можно увидеть на варианте с обычным вызовом скрипта . Диаграмма загрузки изображена на рис. 1.

Рис. 1. Диаграмма загрузки скриптов в обычном случае.

Хотя сортировка данных в таблице и работала, это не сделало меня счастливее, ибо загрузка страницы замедлилась. На рис. 1 хорошо видно, как моя версия скрипта (по имени sorttable-async.js) блокирует все остальные HTTP-запросы на странице (в частности, arrow-right-20x9.gif), что замедляет загрузку страницы. Все диаграммы загрузки сняты при помощи Firebug 1.3 beta . В этой версии Firebug красной линией отображается событие onload . (А синяя линия соответствует событию domcontentloaded .) Для версии с обычным вызовом скрипта событие onload срабатывает на 487 миллисекунде.

Скрипт sorttable-async.js не является необходимым для первоначального отображения страницы: сортировка столбцов возможна только после того, как сами столбцы отрисованы. Такая ситуация (внешние скрипты, которые не используются для первоначального отображения страницы) является кандидатом номер 1 для внедрения асинхронной загрузки. Вариант с асинхронной загрузкой скриптов подключает этот скрипт, используя DOM-методы для создания нового тега script:

var script = document.createElement("script"); script.src = "sorttable-async.js"; script.text = "sorttable.init()"; // это объясняется в следующем разделе document.getElementsByTagName("head").appendChild(script);

Диаграмма HTTP-загрузки для асинхронной загрузки скриптов изображена на рис. 2. Стоит обратить внимание, как асинхронный подход предотвращает блокирующее поведение: sorttable-async.js и arrow-right-20x9.gif загружаются параллельно. Это снижает общее время загрузки дл 429 мс.

Рис. 2. Диаграмма загрузки скриптов в асинхронном случае

Шаблон двойного скрипта от John Resig

Позволяет укорить загрузку страницы, но в этом случае остается, что улучшить. По умолчанию сортирующий скрипт вызывает «сам себя» при помощи прикрепления sorttable.init() в обработчику события onload для этого скрипта. Некоторое улучшения производительности (и уменьшение кода ) может быть достигнуто, если вызвать sorttable.init() внутри тега script , чтобы вызвать его сразу же после загрузки внешнего скрипта (подключенного через src ). В этом случае в качестве "API" я использую одну-единственную функцию, но я предполагаю, что этот случай иллюстрирует максимально расширяемый шаблон, позволяющий использовать внешний модуль безо всяких предположений о его дальнейшем использовании (классическая ситуация использования JavaScript-логики от внешних разработчиков ).

Я уже описал три способа по стыковке внутреннего кода с асинхронной загрузкой внешних скриптов: window onload , onreadystatechange у скрипта и встроенный в скрипт обработчик. Вместо всего этого я использовал технику от John Resig — шаблон двойного тэга script . John описывает, как связать внутренние скрипты с загрузкой внешнего файла следующим образом:

jQuery("p").addClass("pretty");

В этом случае код внутри срабатывает только после того, как загрузка (и инициализация ) внешнего скрипта завершилась. У этого подхода по стыковке скриптов есть несколько очевидных преимуществ:

  • проще: один тег script вместо двух
  • прозрачнее: связь внутреннего и внешнего кода более очевидная
  • безопаснее: если внешний скрипт не загрузится, внутренний код не будет выполнен, что предотвратит появление ошибок, связанных с неопределенными переменными

Это замечательный шаблон для асинхронной загрузки внешних скриптов. Однако чтобы его использовать нам придется внести изменения как во внутренний код, так и во внешний файл. Для внутреннего кода мне пришлось добавить уже упомянутую выше третью строку, которая выставляет свойство script.text . Для завершения процесса стыковки нужно добавить в конец sorttable-async.js:

var scripts = document.getElementsByTagName("script"); var cntr = scripts.length; while (cntr) { var curScript = scripts; if (-1 != curScript.src.indexOf("sorttable-async.js")) { eval(curScript.innerHTML); break; } cntr--; }

Этот код проходится по всем скриптам на странице, находит необходимый блок, который должен загрузить сам себя (в этом случае это скрипт с src содержащим sorttable-async.js). Затем он выполняет код, которые добавлен к скрипту (в этом случае sorttable.init()) и таким образом вызывает сам себя. (Небольшое замечание: хотя при загрузке скрипта текст в нем был добавлен при помощи свойства text , обращение к нему происходит при помощи свойства innerHTML . Это необходимо для обеспечения кроссбраузерности.) При помощи такой оптимизации мы можем загрузить внешний файл скрипта, не блокируя загрузку других ресурсов, и максимально быстро выполнить привязанный к данному скрипту внутренний код.

Стоит также заметить, что описываемая техника может быть заменой только прямой модификации внешнего скрипта. В случае невозможности такой модификации мы можем использовать только установление проверки загрузки по интервалу:

var _on_ready_execution = setInterval(function() { if (typeof urchinTracker === function) { urchinTracker(); clearInterval(_on_ready_execution); } }, 10);

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

Однако в случае проверки по интервалу нам совсем не нужно модифицировать внешний файл, в случае же двойного использования тега script это просто необходимо. Проверку по интервалу можно улучшить, если по истечению некоторого времени (5-10 секунд, например) перезапускать загрузку внешнего файла (меняя исходный тег script при помощи уникального GET-параметра), а после нескольких неудачных перезапусков вообще прекращать загрузку (возможно, с каким-то сообщением об ошибке).

Ленивая загрузка

Общее время загрузки может быть уменьшено еще больше, если использовать «ленивую загрузку» скрипта (загружать его динамически как часть обработчика события onload). Пример такого поведения расположен на странице с

Поводом к написанию этого поста послужило то, что не раз мне приходилось замечать, что вставка на страницу кода кнопок различных сервисов (например: вконтакте, фейсбук, твиттер, одноклассники) приводила к заметному замедлению загрузки и отображения страницы. Речь идет о том случае, когда используется подключение внешних javascript этих социальный сервисов.
Если мы используем простые статичные графические кнопки, никаких проблем нет, т.к. это минимум графики и скриптов, которые расположены локально (можно посмотреть пример реализации тут http://pervushin.com/social-button-for-blog.html). Но мы видим только иконки соц. сервисов, никакой статистики (сколько нашу страницу "залайкнули") нет. Т.е. если мы хотим видеть и статистику, то придется подключать внешние скрипты. И тут стоит иметь в виду, что сколько таких кнопок мы подключили, то столько внешних скриптов браузер вынужден скачать, т.е. это дополнительные подключения к внешним серверам.

Чтобы показать, что происходит, если на странице есть скрипты в секции , предлагаю рассмотреть ряд тестовых примеров. Я буду использовать FireFox 3.6 и FireBug.

Итак:
1) Простейшая страница с одним файлом стилей, двумя скриптами и тремя картинками:













А вот диаграмма загрузки для нее:

Обратите внимание, что все картинки грузятся только после загрузки самого "долгого" javascript файла.
Я намеренно сделал довольно длительной загрузку dummy_css.css и dummy_js.js. Это просто два файла:

dummy_css.php

html, body {
margin:0;
padding:0;
}
.img_container{
margin:0 auto;width:500px;
}

dummy_js.php


var param=1;

Итак, видно что js файл блокирует загрузку всей остальной графики.

2) Все почти то же самое, но dummy_ js. js грузится с внешнего хоста:

Ситуация аналогична предыдущей:

3) Попробуем поменять в секции head местами css и js файлы (css теперь идет после js):







Смотрим на диаграмму загрузки:

Js по-прежнему блокирует загрузку картинок, независимо от того, с какого хоста он грузится.

4) Увеличим по времени загрузку css до 4-х секунд (html код как в случае N3):

5) Еще один интересный случай: css располагается до js, но css грузится дольше















Тут уже css блокирует загрузку картинок...

6) Переносим один js внутрь < body>
















Видно, что dummy_ js. js блокирует загрузку только третьей картинки, которая расположена в html коде после него. Но если css грузится дольше, то тогда уже он будет блокировать загрузку графики. Нетрудно представить, что подключаемые внешние скрипты могут сильно замедлить загрузку и отрисовку страницы, особенно если удаленный сервер по каким-то причинам долго отвечает.

Размещение внешних скриптов перед

Что сразу напрашивается... Все скрипты, загрузка которых не критична для страницы, стоит выносить прямо перед закрывающим тегом . Но это можно сделать для тех скриптов, в которых вся логика находится внутри и нет внешних вызовов из html кода. Если же из html кода делается вызов каких-то функций из еще не загруженных скриптов, то такие ситуации надо обрабатывать особым образом, т.к. нужно отслеживать загрузку.

Но есть еще одна проблема, поясню на примере:




$("img").click(function() {
alert($(this).attr("src"));
});
});






Если js перед будет грузиться долго, то клики по картинкам до полной загрузки этого скрипта ни к чему не приведут, т.к. $(document).ready() сработает только после полной загрузки js. Так что если на страницах есть некая логика, которая предусматривает обработку событий, то этот способ мало подходит.

Итак, что нужен способ неблокирующей загрузки скриптов...

Создаем async.js:



script.src = "dummy_js.js";


и подключим его:











$(document).ready(function() {
$("img").click(function() {
alert($(this).attr("src"));
});
});






Если вызов async.js разместить в ,а не перед , то диаграмма получится такая:

Но если в коде все-таки удобнее размещать async.js именно в , то следует немного поменять содержимое async.js:

$(document).ready(function() {
var script = document.createElement("script");
script.src = "dummy_js.js";
document.getElementsByTagName("head") .appendChild(script);
}
);

Итак, вопрос асинхронной загрузки решен, но остается открытым вопрос синхронизации загрузки внешних скриптов и кода, их использующих. Рассмотрим его на практике, подключая кнопки социальных сетей.

Как-то моя любимая мама, абсолютно не подкованная в вопросе онлайн-рекламы, рассказала, что в интернете ее повсюду преследовали фритюрницы от бренда Moulinex: “Это было так странно. Я трижды наткнулась на них в Facebook, и решила купить. Наверное, это знак свыше.”

Мне не хватило цинизма рассказать ей, что это никакая не судьба, а просто навязчивый ретаргетинг. Все мы хотя бы раз были жертвами ремаркетинга. В этой статье, я покажу как использовать эту технологию себе на пользу — показывать рекламу только тем, кто уже заинтересован в вашем товаре или услуге. Как правильно настроить рекламную кампанию в Фейсбуке?

Что такое ремаркетинг (ретаргетинг)?

Если вам незнаком этот термин, то ремаркетинг позволяет интернет-магазинам везде следовать за потенциальными покупателями, и показывать им релевантную рекламу. Когда посетители попадают на ваш сайт, это записывается в cookies. Впоследствии им на страницах других сайтов и соц.сетей показывается реклама того, чем они когда-то интересовались на вашей площадке, будь то социальные сети или другие интернет-магазины.

То есть, когда вы на баннерах других сайтов видите рекламу холодильников, которые только недавно просматривали в интернет-магазине, это никакая не судьба, это ремаркетинг.

Ремаркетинг предстает перед нами в различных формах и размерах. Например, я уже рассказывал о , вы можете таргетировать всех посетителей сайта или исключительно тех, кто посещал только определенную страницу или совершал определенные действия. Позже Google показывает этим людям те же самые или схожие товары, но уже в виде рекламы на других сайтах, задействованных в контекстно-медийной сети Google.

Как работает ремаркетинг в Facebook?

Ремаркетинг в Facebook работает по тому же принципу, что и в Google AdWords, только вместо отображения вашей рекламы в рамках медийной сети, они показываются в ленте фейсбука.

В Facebook предпочитают называть ремаркетинг «Custom Audiences» или “индивидуальная аудитория ”. Суть та же: кто-то заходил на ваш сайт или взаимодействовал с вашим брендом, на них ставится метка в виде кода для отслеживания, а затем ваша реклама показывается им, когда они просматривают ленту новостей в Facebook.

По правде говоря, в ремаркетинге Facebook есть дополнительные преимущества в виде возможности создавать списки клиентов, таргетировать по трафику веб-сайта или действиям в приложениях.

1. Списки клиентов

Вероятно, один из мощнейших инструментов в арсенале Facebook – возможность показывать персонализированные объявления списку клиентов, которых вы уже собрали до этого.

При помощи списков клиентов реклама в Facebook становится все больше похожей на email-маркетинг, и позволяет таргетировать определенных людей при помощи персонализированных сообщений. Будь то email-адрес, номер телефона или даже ID пользователя в Facebook, вы можете извлечь список контактов из (или где там у вас хранится клиентская база), напрямую загрузить их в Facebook и таргетировать людей релевантной рекламой.

2. Посетители сайта

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

Например, если вы продаете экипировку для бега, но рекламой в Facebook вам нужно охватить тех, кто ищет кроссовки, то можно настроить индивидуальную аудиторию, поместив туда только тех людей, кто просматривал страницы с ключевым словом «кроссовки» в URL.

3. Действия в приложениях

Наконец, вы можете таргетировать пользователей по активности в . Если есть собственное популярное приложение, то это хороший вариант. К тому же здесь представлено несколько способов показывать релевантную рекламу людям, основываясь на действиях, которые они совершают в мобильных приложениях.

Например, если кто-то бросил корзину внутри вашего приложения, вы можете повторно привлечь этих людей, предложив им тот же или похожий товар, но уже со скидкой. Можно охватить людей, которые недавно открывали ваше приложение и покупали что-то (предложить сопутствующие товары, например), или которые долго играли в вашу игру и забросили играть на каком-то конкретном уровне.

Почему стоит использовать ремаркетинг?

А почему нет?

Ремаркетинг – это настолько просто, что было бы глупо игнорировать такую возможность! Перед вами плоды на низких ветках, просто соберите их при помощи списка аудиторий в Facebook и ретаргетинга на сайте.

Еще неуверены? Учитывая тот факт, что аудитория Facebook намного более платежеспособна, чем пользователи Вконтакте и других наших социальных сетей, перспективы по развитию бизнеса при помощи этого канала практически безграничны. И почему бы не начать со знакомых лиц?

Взгляните на это как на романтические отношения 😉 Вам будет комфортнее пойти на второе свидание с тем, с кем вы уже провели приятный вечер, нежели на свидание вслепую, когда о развитии событий можно лишь предполагать?

То же касается рекламы. Если кто-то уже заходил к вам на сайт, скачивал бесплатную электронную книгу или использовал ваше приложение, то шансы, что он увидит вашу рекламу на Facebook и купит что-нибудь гораздо выше. По факту, объявления для ремаркетинга на Facebook привлекают в 3 раза больше людей, чем обычные рекламные объявления .

Как запустить ретаргетинг в Facebook?

Чтобы начать ремаркетинг, перейдите в раздел Менеджер рекламы , выберите пункт «Инструменты» и затем «Аудитории».

Выберите пункт «Создать индивидуализированную аудиторию».

Список клиентов

Импортировать список клиентов можно либо посредством копирования и вставки, либо при помощи загрузки файла, который содержит email-адреса, телефоны и/или ID пользователей в Facebook (или ID мобильного рекламодателя). В Facebook также предусмотрена интеграция с сервисами , чтобы загрузить список тех людей, которые уже являются вашими подписчиками.

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

Трафик веб-сайта

Перед таргетингом рекламы по посетителям сайта, вам нужно создать и установить Facebook-пиксель на все страницы вашего сайта (примечание: если ранее вы уже устанавливали этот пиксель — пропуститите этот шаг). Сделать это нужно один раз, так как на каждый рекламный аккаунт выделяется по одному пикселю для ремаркетинга посетителей. Для этого вам нужно:

  • Вернуться к выпадающему меню Инструменты, расположенному вверху страницы.
  • Выбрать «Пиксели».
  • Создать пиксель.
  • Задать название и создать собственный пиксель.

Если вы не умеете вставлять код в страницы, то поручите это своему разработчику. Код пикселя помещается в заголовочную часть сайта, в теге «header». Пиксель не начнет собирать аудиторию до тех пор, пока вы не создадите аудиторию, привязанную к рекламной кампании.

Теперь вернитесь к меню создания индивидуализированной аудитории, и выберите там пункт «Трафик веб-сайта». На этой странице вы можете указать параметры, которым должен отвечать посетитель для того, чтобы попасть в категорию ремаркетинга. Например, все, кто посещал сайт или только те, кто открывал конкретные страницы, в URL которых содержится слово «obuv» (пер. «обувь»). Дайте название этой аудитории (например: «все посетители», «покупатели обуви» и т. д.), и нажмите «Создать аудиторию».

Как только разберетесь с индивидуализированной аудиторией, вам понадобится добавить ее к группам объявлений, которые вы создавали до этого или же создать новый набор, к которому можно будет привязать ту или иную аудиторию.

5 примеров ретаргетинга на Facebook

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

1. Привлекайте подписчиков

Хотите нарастить количество лайков на ? Обычно этими метриками отчитываются о проделанной работе перед начальством или просто укрепить доверие к бренду в социальных сетях, но не лучше иметь много подписчиков? Сразу скажу, что набирать их естественным путем будет сложно и долго. К счастью, в Facebook можно запускать платные кампании, с целью раскрутки страницы (смотрите скриншот ниже).

Если вы рекламировались в AdWords, то наверняка знакомы с тем, как показатель качества контента () влияет на ранжирование объявлений, а также плату за клик. У Facebook есть похожая метрика, которая называется показателем релевантности , и именно она определяет ваш бюджет и частоту показа объявлений для ЦА. Наиболее влиятельным аспектом для релевантности считается показатель вовлеченности, который точно увеличиться, если ваша реклама отображается для тех, кто уже заинтересован в ваших товарах и услугах.

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

Кроме того, отмечу небольшой бонус в виде бесплатного охвата. Если кто-то из подписчиков на Facebook «лайкает» запись на вашей странице, скорее всего она покажется его друзьям, а это, в свою очередь, способствует все новым лайкам и подписчикам!

2. Ретаргетинг на людей, которые уже лайкнули вашу страницу

Теперь, когда есть подписчики, убедитесь, что они видят ваши посты, и проявляют активность. Дополните 1-й пункт ремаркетингом продвигаемых вами постов, нацелившись на подписчиков в Facebook. Под каждым постом на вашей странице расположена кнопка «поднимать».

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

Это проверенный метод, так как люди не просто уже взаимодействовали с вашим брендом, но и сталкивались с ним на той же платформе, где ретаргетинг – на Facebook. Если пользователь лайкнул страницу компании, считайте, что он уже проявил лояльность, и вероятность того, что он заинтересуется в ваших постах, гораздо выше. Это, опять же, ведет к увеличению показателя релевантности и органическому охвату ЦА.

3. Используйте демографический таргетинг

Уровень сегментирования аудитории, который можно достичь при помощи опций таргетинга на Facebook просто поражает. Таргетинг распознает всех, от молодых мам до премьер-министров, и если вы знаете свою аудиторию, у вас не возникнет проблем с ее поиском. И хотя очень важно не переборщить и не сузить нарочно охват, еще важнее распределить бюджет так, чтобы о вашем бренде действительно узнавали заинтересованные люди, иначе показатель релевантности будет понижаться, как и прибыль.

Давайте предположим что ваша аудитория для ремаркетинга получается достаточно широкой. Вот, вы загрузили список из более 1000 контактов, но вы готовы потратить лишь 5000Р. Вместо того чтобы думать и гадать, куда потратить очередной рубль, лучше совместить этот список контактов с демографическим таргетингом, что может выявить близкую , заинтересованную в вашем продукте.

Все дело в поиске правильного баланса между бюджетом и размером аудитории, но эксперименты посредством опций таргетинга однозначно помогут вам увеличить релевантность и распределить бюджет наиболее эффективно.

4. Планируйте расписание показов рекламы

Жизнь объявления в Facebook коротка, но вместо того, чтобы запускать его снова и снова, пока не растратите деньги, задумайтесь о цели этого объявления. Может быть, вы планируете распродажу в Черную пятницу, какие-то космические скидки или выгодное предложение при покупке мебели набором? Тогда крутите рекламу, пока эти предложения действуют, без ограничения показов, и желательно в качестве списков для ретаргетинга отмечать именно тех людей, кто недавно смотрел нечто подобное на сайте. Если же вы просто рекламируете страницу всем посетителям сайта, то следует время от времени менять его содержимое и картинку.

Подобно AdWords, также доступна настойка расписания для показа объявлений по дням недели и часам. Если вы представляете IT-компанию и знаете, что повышение трафика и продаж обычно отмечается с понедельника по пятницу с 9 до 17, то выставите соответствующее расписание для показа.

Мораль сей истории в том, что когда вы настраиваете группы объявлений, старайтесь стратегически подходить к расписанию, чтобы не слить бюджет.

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

Анализируем результаты

Для начала, позвольте мне сказать очевидное: все зависит от ниши, и вряд ли есть какие-то универсальные подходы. Сегодня у большинства кампаний по ретаргетингу высокий ROI. Чтобы определить эффективность вашей рекламной кампании, пользуйтесь функцией «Отчеты» в Power Editor. Я рекомендую дождаться как минимум 500 просмотров или даже тысячу, перед тем, как останавливать показ объявлений.

Вебинар по этой теме


Интервью про грамотное продвжение в FB