как вставить скрипт в браузер
Инструкция по запуску Java-скриптов в браузерах Firefox, Chrome, IE, Opera, Safari и других
На нашем сайте опубликовано уже множество различных Java-скриптов для социальных сетей. И в описании каждого скрипта описывать подробные инструкции по их запуску… Это ни к чему. Мы решили написать полноценный мануал с описанием установки скриптов на все браузеры, а также учесть наличие нескольких способов установки на один конкретный браузер и описать их все.
Запуск Java-скриптов через консоль браузера
Сейчас, как известно, запуск скриптов через консоль является наиболее популярным и простым, а главное рабочим способом их использования. Следовательно, с этого мы и начнём – со способов попасть в консоль для каждого браузера.
Консоль в Mozilla Firefox
Проще всего попасть в веб-консоль в браузере Mozilla Firefox можно при помощи сочетания клавиш Ctrl + Shift + K. Нажмите и консоль отобразится.
Консоль в Google Chrome и других браузерах, основанных на Chromium
В Google Chrome, Opera 15+, Амиго, Orbitum и других браузерах, основанных на Chromium, также имеется способ запуска веб-консоли при помощи горячих клавиш. Для этого нужно одновременно нажать Ctrl + Shift + J.
Консоль в Opera 12
Чтобы запустить веб-консоль в браузере Opera старого поколения (не старше 12-ой версии), нужно использовать сочетание клавиш Ctrl + Shift + I. Это позволит запустить Opera Dragonfly – панель с инструментами для разработчика. После её открытия перейдите на вкладку Консоль.
Консоль в Internet Explorer
Чтобы открыть консоль в веб-браузере Internet Explorer, необходимо сначала нажать на кнопку F12, а затем нажать сочетание Ctrl + 2 (двойка на центральной панели, а не в секции Num).
Консоль в Safari
В Safari, перед открытием консоли, обязательно нужно войти в настройки браузера (шестерёнка в правом верхнем углу » Настройки… » Дополнения) и подключить опцию Показывать меню «Разработка» в строке меню. После этого, консоль можно будет вызывать сочетанием клавиш Ctrl + Alt + C.
Все скрипты вводятся в консоли в специально отведённое поле рядом с иконкой-стрелочкой (см. скриншоты, зоны для ввода скриптов выделены красной рамкой). Запуск скриптов осуществляется нажатием кнопки Enter. После ввода и запуска любого скрипта вы будете видеть все комментарии или ошибки в ходе их выполнения.
Запуск Java-скриптов из адресной строки браузера
Метод запуска скриптов из адресной строки браузера является более старым методом, а скорее даже традиционным. Изначально, все скрипты запускались именно таким образом. Но тенденции меняются, мир развивается. В большинстве браузеров после вставки кода скрипта в адресную строку нужно дописывать код вручную, чтобы запустить, а в некоторых браузерах адресная строка вообще не обрабатывает java-скрипты.
Адресная строка в Mozilla Firefox
Печально, но ни одна из самых последних версий браузера Mozilla Firefox не поддерживает обработку скриптов через адресную строку. Хоть и в более ранних версиях подобная опция присутствовала, в современном Firefox разработчики решили от этого отказаться.
Адресная строка в Google Chrome и других браузерах, основанных на Chromium
В браузере Google Chrome и любом другом браузере, построенном на его исходных кодах, таких, например, как Opera 15+, Amigo, Orbitum и других, можно запускать скрипты в адресной строке. Но! После вставки скрипта, перед ним обязательно нужно дописывать слово javascript: (вместе с двоеточием), иначе (благодаря такому явлению, как omnibox) вместо запуска скрипта будет происходить перенаправление на поисковую систему.
Адресная строка в Opera 12
В браузере Opera 12 всё обстоит намного лучше. Для запуска скрипта достаточно вставить его в адресную строку и запустить. Никаких проблем при этом возникать не должно.
Адресная строка в Internet Explorer
В данном браузере, как и в Google Chrome и ему подобных, после вставки скрипта в адресную строку, в самом начале нужно дописать javascript: (вместе с двоеточием), иначе скрипт не заработает.
Адресная строка в Safari
Ну а в Safari дела обстоят так же хорошо, как и в Opera 12. Просто вставьте имеющийся скрипт в адресную строку и запустите.
Использование браузерных плагинов для хранения и запуска скриптов
Если скрипты нужно использовать постоянно, то необходимо возиться с ними, копировать с сайта или текстового файла, вставлять в адресную строку или консоль каждый раз. Согласитесь, – это не удобно. Именно поэтому были придуманы специальные расширения (плагины) для браузеров, предназначенные для хранения и запуска скриптов. Речь пойдёт о двух плагинах: Greasemonkey для Mozilla Firefox и Tampermonkey для Google Chrome.
Плагин Greasemonkey для Mozilla Firefox
Плагин Greasemonkey для Mozilla Firefox позволяет создавать, сохранять и запускать скрипты, добавленные пользователями. Будьте внимательны! При использовании скриптов для удаления или изменения чего-либо, сразу после их добавления в плагин они будут запущены автоматически. Настоятельно не рекомендуем добавлять в плагин скрипты, к примеру, для удаления записей со стены ВКонтакте при открытой странице ВКонтакте (мало ли что).
Плагин Tampermonkey для Google Chrome
Плагин Tampermonkey является аналогом плагина Greasemonkey для Firefox и точно также позволяет создавать, сохранять и запускать пользовательские скрипты. Будьте внимательны! При использовании скриптов для удаления или изменения чего-либо, сразу после их добавления в плагин они будут запущены автоматически. Настоятельно не рекомендуем добавлять в плагин скрипты, к примеру, для удаления записей со стены ВКонтакте при открытой странице ВКонтакте (мало ли что).
Вот так работают плагины Greasemonkey и Tampermonkey. Всё быстро и просто. Добавленные скрипты никуда не пропадают, их также можно включать и выключать в любое удобное время.
Заключение
Все описанные способы запуска Javascript описаны для самых последних версий популярных веб-браузеров. Если вы используете другой браузер или более устаревшую версию браузера, и способы запуска скриптов в нём отличаются от описанных в данной статье, просьба сообщить об этом в комментариях.
Делаем своё расширение для браузера за 10 минут
Cнова запускаем снежинки.
В конце 2020 года мы делали проект со снежинками — писали специальный скрипт, который запускал падающий снег на сайтах. Если бы мы хотели сделать такой снег на любом своём сайте, это не составило бы труда: добавляешь скрипт в код страницы, и готово.
А вот на чужих сайтах была проблема. Скрипт нужно было вставлять через консоль. А если на сайте была настроена политика безопасности, которая запрещает запуск внешних скриптов, то магия не срабатывала.
Сегодня мы это исправим — сделаем расширение для браузера, которое может запускать любой скрипт на любой странице. Мы охватим принцип, на основе которого вы сможете сделать собственные расширения, в том числе намного более сложные.
👉 Что такое расширение
Расширение для Chrome — это небольшая программа, которая выполняется внутри браузера и помогает расширить возможности сайтов. Сила расширения в том, что оно может выполняться прямо из меню браузера и не зависит от политик безопасности.
Примеры того, что может сделать расширение:
В этой статье
Мы сделаем самое простое расширение для браузера Chrome, которое позволит запускать скрипт со снежинками на любом сайте, независимо от настроенной политики безопасности. Для этого воспользуемся официальным руководством Google по созданию расширений.
Манифест
В каждом расширении для браузера должен быть манифест — документ, в котором написано:
Манифест задаёт общие правила для всего расширения, поэтому манифест — единственный обязательный компонент. Можно обойтись без иконок и скриптов, но манифест обязательно должен быть.Каждый манифест хранится в файле manifest.json — создадим пустой файл с таким именем и напишем внутри такое:
<
«name»: «Запускаем снежинки на любом сайте»,
«description»: «Проект журнала Код»,
«version»: «1.0»,
«manifest_version»: 3
>
Первые две строчки — это название и подробное описание расширения. Третья отвечает за номер версии расширения, а последняя говорит браузеру, какая версия манифеста используется в описании. На момент выхода статьи в феврале 2021 года используется третья версия.
Сохраняем файл и всё, расширение готово. Оно ничего не умеет, ничего не делает, зато мы уже можем добавить его в браузер. Для этого запускаем Хром и в адресной строке пишем:
Мы попадаем на страницу, которая нам покажет все установленные расширения:
Чтобы добавить своё расширение, в правом верхнем углу включаем режим разработчика, а затем нажимаем «Загрузить распакованное расширение»:
Теперь выбираем папку, в которой лежит наш манифест:
Отлично, мы только что добавили в браузер новое расширение:
Теперь мы можем обновлять наш манифест, класть в ту же папку дополнительные файлы, а для обновления в браузере достаточно будет нажать на круглую стрелку на карточке расширения.
Чтобы было проще работать и тестировать расширение, закрепим его на панели браузера:
Иконки
У расширения есть две иконки, которыми мы можем управлять:
Чтобы не рисовать всё с нуля, скачаем папку с иконками из того же руководства Google и положим её в ту же папку, что и манифест:
Теперь добавим иконки в манифест. За картинку в карточке отвечает блок icon, а за иконку на панели — блок action. Разные размеры картинки нужны для того, чтобы на разных мониторах с любой плотностью пикселей иконки выглядели хорошо:
Сохраняем манифест, обновляем расширение на странице настроек и смотрим результат:
Настраиваем разрешения
Разрешения — это то, что браузер позволяет делать расширению со страницами и с их содержимым. Для запуска снежинок нам нужно сделать две вещи:
Чтобы получить доступ к активной вкладке и к запуску скриптов, добавим в манифест такую строку:
«permissions»: [«activeTab», «scripting»],
Показываем меню
Если мы сейчас нажмём на иконку расширения на панели браузера, то ничего не призойдёт, потому что мы ничего не запрограммировали. Исправим это — сделаем так, чтобы при нажатии расширение показывало кнопку запуска. Когда расширение будет уметь больше, вместо одной кнопки можно будет показать целое меню.
Чтобы сделать всплывающее меню, добавим в манифест в раздел action такую строку:
Она означает, что при нажатии на иконку мы увидим рядом с ней мини-страничку, на которой что-то будет.Создадим в той же папке расширения файл popup.html и добавим в него такой код:
Сохраняем манифест, обновляем его на странице настроек и видим, что у нашего расширения появилось меню с кнопкой:
Запускаем снежинки
Вся магия будет происходить в файле popup.js — откроем его и добавим такой код:
Последнее, что нам осталось сделать, — положить в функцию snowFall() полный код скрипта из проекта со снежинками и сохранить файл.
Проверка
В прошлый раз мы не смогли запустить скрипт на любой странице Яндекса — мешала политика безопасности. Теперь всё работает:
Скачать упакованное расширение. Перед установкой его нужно распаковать в любую папку.
Погружение в темные воды загрузки скриптов
Введение
В этой статье я хочу научить вас как загружать в браузер JavaScript и выполнять его.
Нет, подождите, вернитесь! Я знаю, что это звучит заурядно и просто, но помните, что это происходит в браузере, где теоретически простое превращается в набор причуд, определенных наследственностью. Знание этих причуд поможет вам выбрать самый быстрый, наименее разрушительный способ загрузки скриптов. Если вы спешите, то можете перейти сразу к краткому справочнику в конце статьи.
Для затравки, вот как спецификация определяет различные способы загрузки и выполнения скриптов:
Как и все спецификации WHATWG, на первый взгляд данная спецификация выглядит как последствия кассетной бомбы на фабрике Scrabble. Но, прочитав ее на 5 раз и вытерев кровь из своих глаз, начинаешь находить ее довольно интересной:
Мое первое подключение скрипта
Ах, блаженная простота. В данном случае браузер скачает оба скрипта параллельно и выполнит их как можно скорее, сохраняя заданный порядок. «2.js» не будет выполняться пока не выполнится «1.js» (или не сможет этого сделать), «1.js» не выполнится пока не выполнится предыдущий скрипт или стиль, и т.д. и т.п.
Вот почему гуру и специалисты производительности советуют размещать элементы script в конце документа, потому что это блокирует меньше всего контента. К сожалению, это означает, что ваш скрипт не будет увиден браузером до того времени, как будет скачен весь HTML, а также уже запущена загрузка CSS, картинок и iframe-ов. Современные браузеры достаточно умны, чтобы отдавать приоритет JavaScript над визуальной частью, но мы можем сделать лучше.
Спасибо, IE! (нет, я это без сарказма)
WHATWG сделали это поведение явным, объявив, что «defer» не будет иметь никакого эффекта на скрипты, которые были добавлены динамически или не имеют «src». В противном случае, скрипты с «defer» должны запускаться в заданном порядке после того, как документ был распарсен.
Спасибо, IE! (ну ладно, теперь с сарказмом)
Одно дали — другое отобрали. К сожалению, есть неприятный баг в IE4-9, который может спровоцировать выполнение скриптов в неверном порядке. Вот что происходит:
Допустим, что на странице есть параграф, ожидаемый порядок логов — [1, 2, 3], но в IE9 и ниже результат будет [1, 3, 2]. Некоторые операции DOM вынуждают IE приостановить выполнение текущего скрипта и перед продолжением начать выполнение других скриптов в очереди.
HTML5 спешит на помощь
HTML5 дал нам новый атрибут «async», который предполагает, что вы также не используете document.write, но при этом не ожидает окончания парсинга документа. Браузер параллельно скачает оба скрипта и выполнит их как можно скорее.
К сожалению, так как они постараются выполниться максимально скоро, «2.js» может выполниться раньше «1.js». Это отлично, если они не зависят друг от друга. Например, если «1.js» — это отслеживающий скрипт, не имеющий ничего общего с «2.js». Но если «1.js» — это CDN-копия jQuery, от которой зависит «2.js», то ваша страница будет устлана ошибками, как после кассетной бомбы в… я не знаю… здесь я ничего не придумал.
Я знаю, нам нужна JavaScript-библиотека!
В Святом Граале содержится набор скриптов, загружающихся сразу, без блокирования отрисовки страницы и выполняющихся максимально скоро, в том порядке, в котором мы их добавили. К сожалению, HTML ненавидит вас и не позволит вам этого сделать.
Проблема была решена с помощью JavaScript на разный манер. Некоторые способы требовали от вас вносить изменения в JavaScript, оборачивать всё в callback, который библиотека вызовет в правильном порядке (например, RequireJS). Другие использовали XHR для параллельной загрузки, а затем eval() в нужном порядке, который не работает для скриптов на другом домене, если там нет заголовка CORS и поддержки его в браузере. Некоторые использовали даже супер-магические хаки, как это было сделано в последнем LabJS.
Хаки всяческим образом обманывали браузер, чтобы тот загружал ресурс, вызывая при этом событие по окончанию загрузки, но не начинал его выполнение. В LabJS скрипт сначала добавлялся с некорректным mime-типом, например
Скрипты, которые созданы и добавлены динамически, асинхронные по-умолчанию, они не блокируют отрисовку и выполняются сразу после загрузки, что означает, что они могут появиться в неверном порядке. Однако мы можем явно пометить их неасинхронными:
Это даст нашим скриптам сочетание с поведением, которое не может быть достигнуто чистым HTML. Явно заданные неасинхронными, скрипты добавляются в очередь на выполнение, такую же, как они попадали в нашем первом примере на чистом HTML. Однако, создаваемые динамически, они будут выполняться вне парсинга документа, что не будет блокировать отрисовку, пока они будут загружаться (не путайте неасинхронную загрузку скрипта с синхронным XHR, что никогда не является хорошей вещью).
Скрипт выше должен быть встроен в head страниц, начиная очередь загрузок как можно раньше, без нарушения постепенной отрисовки, и начиная выполнять как можно раньше, в заданном вами порядке. «2.js» может свободно загружаться до «1.js», но он не будет выполнен до тех пор, пока «1.js» успешно не скачается и выполнится или не сможет сделать что-либо из этого. Ура! Асинхронная загрузка, но выполнение по порядку!
Загрузка скриптов этим методом поддерживается везде, где поддерживается атрибут async, за исключением Safari 5.0 (на 5.1 все хорошо). Кроме того все версии Firefox и Opera, которые не поддерживают атрибут async, все равно выполняют динамически-добавленные скрипты в правильном порядке.
Это самый быстрый способ загружать скрипты, так? Так?
Ну если вы динамически решаете какие скрипты загружать — да, иначе — возможно, что нет. В примере выше браузер должен распарсить и загрузить скрипт, чтобы определить какие скрипты загружать. Это скрывает ваши скрипты от сканеров предзагрузки. Браузеры используют эти сканеры для обнаружения ресурсов, которые вы скорее всего посетите следующими и для обнаружения ресурсов страницы пока парсер заблокирован другим ресурсом.
Мы можем добавить обнаружаемость обратно, поместив это в head документа:
Эта статья меня удручает
Ситуация удручающая и вы должны чувствовать себя удрученным. Еще нет декларативного способа без повторений для загрузки скриптов быстро и асинхронно, в то же время управляя порядком выполнения.
С появлением HTTP2/SPDY вы сможете уменьшить накладные ресурсы до точки, где доставка скриптов в маленьких самостоятельно-кэшированных файлах будет самым быстрым способом. Только представьте:
Каждый enhancement-скрипт имеет дело с конкретным компонентом страницы, но требует вспомогательные функции в dependencies.js. В идеале, мы хотим загрузить все асинхронно, затем выполнить enhancement-скрипт как можно раньше, в любом порядке, но после dependencies.js. Это прогрессивное прогрессивное улучшение!
К сожалению, нет декларативного способа для того, чтобы достичь этого, только если модифицировать сами скрипты для отслеживания состояния загрузки dependencies.js. Даже async=false не решит эту проблему, потому что выполнение enhancement-10.js будет заблокировано на 1-9. По факту, есть только один браузер, в котором можно достичь этого без хаков…
У IE есть идея!
IE грузит скрипты не так, как другие браузеры.
IE начинает закачивать «whatever.js» сейчас, другие же браузеры не начнут загрузку до того момента, пока скрипт не будет добавлен к документу. У IE также есть событие «readystatechange» и свойство «readystate», которые сообщают о процессе загрузки. Это на самом деле очень полезно, потому что позволяет нам управлять загрузкой и выполнением скриптов независимо друг от друга.
Хватит! Как я должен загружать скрипты?
Ладно, ладно. Если вы хотите загружать скрипты способом, который не блокирует отрисовку, не требует дублирования и имеет прекрасную поддержку браузеров, то я советую вот этот:
Именно этот. В конце элемента body. Да, быть веб-разработчиком — это как быть царем Сизифом (бум! 100 хипстерских очков за упоминание греческой мифологии!). Ограничения HTML и браузеров не позволяют нам сделать сильно лучше.
Я надеюсь, что модули JavaScript нас спасут, предоставив декларативный неблокирующий способ загружать скрипты и иметь контроль над порядком их запуска, даже если это потребует написание скриптов в виде модулей.
Иуу, должно быть что-то получше, что мы можем использовать сейчас?
Ладно, ради бонусных очков, если вы всерьез думаете о производительности и не боитесь сложности и дублирования, то можете объединить несколько рассмотренных трюков.
Во-первых, мы добавим объявление subresource для предзагрузчиков:
Спецификация говорит: Скачивай вместе, выполняй по порядку после любого ожидающего CSS, блокируй отрисовку, пока не закончишь
Браузер отвечает: Да, сэр!
Defer
Спецификация говорит: Скачивай вместе, выполняй по порядку до DOMContentLoaded. Игнорируй «defer» для скриптов без «src».
IE
Как подключить скрипт на сторонний сайт
Привет, Хабр! Это первый пост в нашем блоге. Многие знают нас как чат для сайта, именно с него мы начинали, а сейчас занимаем лидирующие позиции в сфере бизнес-мессенджеров. Мы постепенно эволюционировали в комплексное бизнес-решение, которое предоставляет множество возможностей для клиентов: callback, общение с клиентами через мессенджеры, соцсети, мобильные приложения, виртуальная АТС, CRM-функции и многое другое.
За несколько лет мы успешно решили множество технических проблем, накопили много интересного, а местами и уникального опыта, конечно же, писали свои костыли и велосипеды. Этим постом мы начинаем серию статей, в которых будем делиться своим опытом разработки, выстраивания процессов в полностью удаленной команде, расскажем про нашу архитектуру, технические решения, которые позволяют нам эффективно обслуживать сотни тысяч клиентов по всему миру.
Jivosite сегодня это:
Входная точка
Театр начинается с вешалки, а подключаемый сервис с кода-вставки. Он является входной точкой для любого сервиса или модуля на сайт. Как правило, его можно найти в инструкции установки, после чего необходимо добавить его в HTML-код сайта, а дальше происходит «магия», которая определенным образом загружает и инициализирует скрипт.
Казалось бы, что может быть проще подключения скрипта на сайт? По стандарту, необходимо просто добавить тег script в HTML-код страницы. Но на самом деле это важный этап, скрывающий много подводных камней. Например, идентификация пользователя, реализация резервного канала загрузки скрипта, настройка внешнего вида или логики, скорость загрузки страницы и так далее. Но давайте обо всем по порядку.
Идентификация
Просто так подключать скрипт мало кому интересно, наверняка скрипт выполняет какую-либо логику, а эта логика привязана к пользователю. Например, ID счетчика, APP_ID от соцсети, в нашем случае это ID созданного канала связи. То есть скрипт должен идентифицировать пользователя в запросах на сервер. Для идентификации клиента через код-вставки есть три варианта реализации.
Передавать ID прямо в ссылке на файл и на стороне сервера каким-либо способом прокидывать его в скрипт. В этом случае серверу на лету придется прописывать ID в файл или формировать JS-строку c ID, которая будет загружать file.js. Эта логика похожа на реализацию JSONP-запросов.
Долгое время мы работали по такому принципу, но минусы этого подхода в том, что добавляется «холостая» нагрузка на сервер и необходимость реализации серверного кэширования.
Атрибут async — говорит браузеру о том, что не нужно дожидаться загрузки скрипта для построения DOM, скрипт надо выполнить сразу после загрузки. Это уменьшает время загрузки страницы, но есть и обратная сторона медали: скрипт может выполняться до того, как DOM будет готов к работе.
Одна из самых популярных реализаций, так делают в том числе и крупные сервисы, отличается только синтаксис, но суть у всех одна.
У такого подхода есть два основных минуса, первый — усложняется код-вставки, а второй — очень важен порядок выполнения данного кода, в противном случае ничего работать не будет. К тому же необходимо делать выбор между скоростью (async) и стабильностью (без async), большинство выбирают 2-й вариант.
Аналогично первому варианту передавать ID в ссылке на файл, но извлекать его в браузере, а не на сервере. Это не так просто, как кажется, но возможно. В API браузера есть свойство document.currentScript, оно возвращает ссылку на скрипт, который загружен и в данный момент выполняется в браузере. Зная это, можно вычислить ID, для этого надо получить свойство document.currentScript.src и регуляркой вытащить из него ID.
Есть одно но: document.currentScript поддерживается не всеми браузерами. Для браузеров, не поддерживающих это свойство, мы придумали интересный хак. В коде file.js можно выбросить специальное «фейковое» исключение, обернутое в try/catch, после чего в стеке ошибки будет URL скрипта, в котором произошла ошибка. URL будет содержать ID, который мы получаем той же регуляркой.
Вот такая магия получается, но это работает. Нет заморочек с порядком выполнения, код-вставки выглядит просто и нет оверхеда на сервере. Последние два года мы используем именно такой подход, хотя сам код-вставки у нас отличается, но принцип тот же.
Настройки
В большинстве случаев у подключаемых скриптов есть какие-либо настройки, отвечающие за внешний вид или логику работы. Эти настройки необходимо «прокидывать» в подключаемый скрипт, для этого существуют два принципиально разных подхода.
К этому подходу также относится передача настроек в GET параметрах url скрипта, аналогично варианту #1 из раздела «Идентификация». Подход заключается в том, что если клиент хочет поменять настройки, то ему необходимо отредактировать код-вставки и обновить его на сайте.
Это хорошо тем, что все настройки хранятся на клиенте и их не надо хранить на сервере, разрабатывать и обслуживать всю связанную с этим бизнес-логику. Главным минусом такого подхода является неудобство для клиента, ему приходится все делать вручную, а если настроек много, то код-вставки превращается в сложно поддерживаемую простыню, в которой легко допустить ошибку. А чтобы обновления вступили в силу, надо обновлять сайт, это лишние телодвижения разработчиков и админов.
Второй подход заключается в том, что в случае необходимости изменения настроек клиенту не надо модифицировать код-вставки, все настройки хранятся на сервере. Для того чтобы поменять настройки, надо зайти в графическую панель, изменить нужные параметры и нажать кнопку «Сохранить». После этого настройки автоматически применятся для его сайта!
Не надо разбираться в коде и делать ради этого деплой, этим может заниматься человек, далекий от JavaScript, например менеджер. Конечно для пользователей такой вариант гораздо удобнее и проще, поэтому именно его мы используем. Но за удобство надо платить, такой подход требует разработки и поддержки логики на сервере и подразумевает дополнительную нагрузку на него. В следующих статьях мы обязательно расскажем, как мы ежедневно обрабатываем 150М таких запросов.
Обратная совместимость
Очень важно максимально быстро прийти к зрелой версии кода-вставки. Потому что обновлять уже установленные коды-вставки будет крайне сложно. Пример из нашей практики: в первых версиях мы использовали числовые ID, но по соображениям безопасности заменили их на число-буквенные. Оказалось, что очень сложно добиться изменения уже установленного кода-вставки. Многие даже не знают, что такое HTML и как устроены сайты. Например, сайт делали фрилансеры, студия или сайт создавался через CMS/конструктор и т. д. В большинстве случаев наши клиенты работают только с панелью настроек виджета. С тех времен у нас до сих пор в nginx работает мапа реврайта старых ID на новые, в которой около 40К записей.
Из-за этой особенности мы вынуждены сохранять обратную совместимость кода-вставки при всех рефакторингах, которых на нашей памяти было около 5.
Изоляция кода
Так как скрипт подключается на сторонний сайт, на котором уже есть JavaScript и CSS код сайта и других сервисов, первостепенной целью является не навредить сайту, чтобы наш код не изменил логику, а тем более не сломал ее. Это может быть JavaScript-ошибка, которая останавливает поток выполнения, или стили, которые переопределяют стили сайта. Но и код сайта может саффектить подключаемый скрипт, например используется библиотека которая модифицирует браузерное API, после чего код перестает работать или работает не так, как мы ожидаем.
Есть разные варианты изоляции кода. Например можно использовать префиксы в JS переменных, замыкания, чтобы не засорять глобальный контекст, использовать что-то наподобие БЭМ для стилей. Но самый простой способ — это выполнения кода в iframe, он решает большинство проблем изоляции, но накладывает определенные ограничения. Мы используем гибридный вариант, про изоляцию кода расскажем подробнее в следующих статьях.
Блокировка загрузки сайта
Событие onload — наступает после того, как веб-страница полностью загружена, включая изображения, стили и внешние скрипты. Важная особенность в том, что на большинстве сайтов JS-логика, сторонние скрипты и реклама начинают работать по наступлению этого события. Очень важным пунктом для всех подключаемых скриптов является не допустить негативного влияния на это событие.
Это происходит в тех случаях, когда сервер, с которого грузится скрипт, отвечает долго или вовсе не отвечает: тогда событие onload откладывается и дальнейшая загрузка страницы по сути блокируется. В случае, когда сервер недоступен, событие onload наступит только по истечении таймаута запроса, который больше 60 с. Таким образом, проблемы на сервере отдачи скрипта по сути «ломают» сайты, что является недопустимым.
Личный опыт
В прошлом я работал в компании, у которой был сайт с одновременным онлайном 100К, онлайн-знакомства. В те времена были попопулярны кнопки «Поделится в соцсетях». Чтобы они появились на сайте, надо было подключить скрипт (sdk) от нужных соцсетей. В один прекрасный день к нам прибежали коллеги и сказали, что наш сайт не работает! Мы посмотрели в мониторинги, в которых все было нормально, и сначала не поняли, в чем проблема. Когда начали разбираться глубже, поняли, что cdn-сервера Twitter прилегли, и их SDK не мог загрузиться, это блокировало нам загрузку сайта на
1.5 минуты. То есть после открытия сайта загружался небольшой HTML(остальное SPA) и только через 1.5 минуты все прогружалось, срабатывал тот самый таймаут запроса. Нам пришлось экстренно организовывать хотфикс и убирать их скрипт с сайта. После повтора этой ситуации мы решили убрать блок «Поделиться» совсем.
В первых версиях кода-вставки у нас не было это учтено, и в случае технических проблем на нашей стороне мы, мягко говоря, доставляли неудобства нашим клиентам, но со временем мы это исправили.
Решение простое, надо подписаться на событие полной загрузки сайта и только потом загружать скрипт, для этого надо использовать код-вставки, а не тег script.
Google Pagespeed
Результаты анализа мобильной версии habr.com
Большинство уделяют внимание скорости загрузки сайта, по многим исследованиям это напрямую влияет на прибыль, к тому же поисковые алгоритмы при ранжирование стали учитывать время загрузки страницы. В связи с этим владельцы сайтов часто используют подобные инструменты для оценки производительности сайта. Поэтому очень важно оптимально подключать код на сайт, так он напрямую влияет на его время загрузки.
Это означает, что надо использовать современные техники оптимизации загрузки страниц. Например использовать Gzip, кешировать статические файлы и запросы, использовать асинхронную загрузки скриптов, сжатие статики современными алгоритмами такими как WebP/Brotli/etc и использовать другие оптимизации. Мы регулярно проводим аудит и реагируем на предупреждения и рекомендации, чтобы соответствовать современным требованиям.
В первых версиях мы загружали статику с серверов приложения. Но у такого подхода есть минусы: дорогой трафик, удаленность от посетителей сайтов и излишняя нагрузка на канал серверов. Можно легко забить канал серверов приложения при хабр-эффекте сайтов, так как трафик статики очень «тяжелый».
С целью экономии бюджета, стабильности и уменьшения сетевой задержки оптимально загружать статику со специально предназначенных для этого серверов. Можно использовать готовые CDN-провайдеры, но на больших масштабах это недешево и приходится ограничиваться возможностями, которое предоставляет тот или иной провайдер.
Мы реализовали это просто, заказали недорогие сервера в России, Европе и Америке с безлимитным трафиком и широким каналом. Это дешево, не накладывает на нас никаких ограничений, мы можем настроить все под себя, а отказоустойчивость обеспечивается за счет механизма, работающего в браузере. В данный момент с наших CDN-серверов загружается 1ТБ статики ежедневно.
Отказоустойчивость
К сожалению, мир не идеален, случаются пожары, аплинки падают, ДЦ целиком уходят под воду, РКН блочит подсети, а люди совершают ошибки. Тем не менее, необходимо уметь обрабатывать такие ситуации и продолжать работать.
Мониторинг
Сначала надо понять, что что-то пошло не так. Можно, конечно, подождать, пока пользователи придут и пожалуются, но лучше настроить мониторинг и алерты, а после релизов, проверять все ли в порядке. Мы мониторим много различных параметров, как серверных, так и клиентских, и если что-то пошло не так, мы сразу это видим. Например, уменьшилось количество загрузок виджета или аномальный всплеск трафика на CDN-серверах.
Суммарное кол-во загрузок виджета по каждой версии
Сбор ошибок
JavaScript очень специфичный язык, и допустить в нем ошибку несложно. К тому же зоопарк браузеров в современном вебе очень большой; то, что работает в последнем Chrome, не факт, что будет работать в Safari или Firefox. Поэтому очень важно настроить сбор ошибок из браузера и вовремя реагировать на всплески. Если ваш код работает в iframe, то сделать это можно отслеживая глобальный обработчик window.onerror и в случае ошибки отправлять данные на сервер. Если код работает вне iframe, то реализовать сбор ошибок очень сложно.
Суммарное кол-ва ошибок со всех сайтов и браузеров
Информация по конкретной ошибке
CDN Failover
Выше я уже писал, что все имеет свойство падать, поэтому важно обрабатывать эти ситуации и лучше — автоматически. Мы прошли несколько этапов фаллбека CDN-серверов, начинали с ручного, а в итоге нашли способ делать это автоматически и оптимально для браузера.
В ручном режиме это работало просто: админам приходило СМС о том что CDN прилег, они совершали определенные манипуляции, после чего виджет начинал загружаться с серверов приложения. Это могло занять от 5 минут до 2 часов времени.
Для реализации автоматического фаллбека необходимо как-то детектить, что загрузка скрипта началась, но сделать это не так просто, как кажется. Браузер не дает возможности отслеживать промежуточные состояния загрузки тега script, как например событие onprogress в XMLHttpRequest, а сообщает только событие по окончанию загрузки и выполнения скрипта. Также нельзя за приемлемое время узнать, что сервер в данный момент недоступен, единственное событие onerror срабатывает по истечении таймаута запроса, больше 1 минуты. За минуту посетитель может уже покинуть страницу, а скрипт так и не загрузится.
Мы пробовали разные варианты, простые и сложные, но в итоге пришли к решению с ping-запросом CDN-сервера. Работает это так: мы сначала пингуем CDN-сервер, если ответил, то тогда мы загружаем виджет с него. Чтобы реализовать эту схему оптимально для браузера и наших серверов, мы используем легкий HEAD-запрос (без тела), а при последующих загрузках мы его не делаем, пока не обновится версия виджета, т. к. виджет уже в кеше браузера.
Таким образом мы получили очень быстрый и автоматически детект доступности сервера статики и в случае падения практически без задержек переходим на резервный сервер.
Loader
Чтобы загрузить свой скрипт на сторонний сайт, надо учесть множество моментов, но реализовать эту логику в коде-вставки сложно, так как он просто превратится в «мясо». Но делать это все равно надо, для этого мы создали небольшой модуль, который управляет всей этой логикой «под капотом» и загружает основной код виджета. Он загружается в первую очередь и реализует CDN Failover, кеширование, обратную совместимость со старыми кодами-вставки, А/Б тестирование, постепенную выкладку новой версии виджета и множество других функций.
Таким образом поэтапно мы пришли к схеме, которая покрывает основные кейсы загрузки и инициализации виджета. Она доказала свою эффективность за годы использования на большом количестве различных сайтов. При этом код-вставки остается простым и универсальным, так как в нем нет никакой логики и мы в любой момент можем ее поменять, при этом не заставляя пользователей менять код-вставки.
Сторонние сервисы
Ну и напоследок стоит упомянуть про сторонние сервисы, которые подключаются на сайт или каким-либо образом взаимодействуют с сайтами: поисковые боты, аналитика, различные парсеры и так далее. Эти сервисы оставляют отпечаток на работе, про это тоже не стоить забывать. Расскажу несколько случаев из нашей практики.
GoogleBot
В нашем приложении оператора есть функция «Посетители», в которой можно посмотреть посетителей, в данный момент просматривающих сайт, и различную информацию по ним: время на сайте, страницу, число просмотренных страниц и так далее. В определенный момент клиенты начали жаловаться, что у них «висят» посетители с других сайтов, то есть на сайте по продаже айфонов, клиент, у которого якобы открыта страница «Купить крем для лица». Когда начали разбираться, выяснили, что это GoogleBot, который при переходе от сайта к сайту кешировал LocalStorage первого и впоследствии передавал неправильные данные на сервер.
Решение простое, на сервере начали игнорировать данные от GoogleBot.
Яндекс.Метрика
В метрике есть замечательная функция — вебвизор, которая позволяет посмотреть, что видел и делал пользователь, в виде скринкаста. Для этого метрика записывает все действия пользователя, а после специальный бот метрики ходит по сайтам, совершает те же действия и записывает это. Проблема была в том, что для эмуляции мобильного браузера пользователя, по нашим данным, включался Firefox в режиме мобильной эмуляции, но при этом userAgent у бота был десктопный.
Это приводило к тому, что при просмотре мобильных пользовательских сессий в вебвизоре на записи открывалась десктопная версия виджета, хотя на самом деле у пользователей открывалась мобильная. Наши клиенты думали, что так и есть, и заваливали нас жалобами. В итоге нам пришлось детектить, что виджет загружен в вебвизоре, понимать, что в нем открыта мобильная версия, и в этом случае подсовывать туда мобильный виджет.
Примеров намного больше, но, думаю, этого будет достаточно для понимания сути.
Заключение
Надо очень внимательно относиться к коду, который вы отдаете клиентам для вставки на сайт. Мы кратко рассказали, с какими проблемами мы столкнулись и как их решали. В следующих статьях мы более подробно расскажем про некоторые упомянутые темы и другие участки нашей системы, например, как мы используем NodeJS в качестве бэкенда, как держим нагрузку всех 270К сайтов за счет продуманного кеширования и не боимся хабра-эффекта подключенных к нам сайтов, как работаем в полностью распределенной команде и многое другое.
Спасибо за внимание, будем рады ответить на ваши вопросы и комментарии!