24 июня 2015

STB — погружение

JavaScriptКлиентская оптимизация
Всем доброго времени суток.

Я думаю что многие из вас слышали о домашнем телевидении, и предложении купить себе в дом ТВ-декодер (приставку) чтобы вы могли насладиться качественным ТВ, покупать фильмы, узнавать погоду, и делать многое другое не отходя от телевизора.

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

image


Что такое приставка?


Приставка (STB, Set-Top Box, бокс) — это одноплатный компьютер, на которой установлена максимально урезанная ось из семейства GNU/Linux.

Команда uname -a:
# uname -a
Linux (none) 3.1.5-1.7 #66 SMP Wed Oct 22 14:40:19 EEST 2014 mips GNU/Linux


Боксы как-правило слабые.
Сильные представители (и, соответственно, дорогие) могут иметь:

  • Оперативная память — от 300Mb до 1Gb
  • Всего места на приставке — ~250Mb
  • Свободного места — ~5-20Mb (возможно, бывает и больше, но это именно те цифры, с которыми приходится работать)
  • Процессор — до 1.3Ghz (до двух ядер)


Каждый бокс имеет (список содержит лишь важные элементы):

  • Ethernet вход — нужен для IPTV (если бокс IPTV), интеграции с сервисами, для подключения к приставке
  • HDMI выход — без комментариев
  • Аналоговый выход — без комментариев
  • S/PDIF — без комментариев
  • USB входы — как-правило один вход, но бывают боксы которые рассчитаны на подключение различных флешек и внешних жестких дисков одновременно, и поэтому могут иметь больше входов. Некоторые боксы даже поддерживают USB-хабы.


В зависимости от задачи бокса и некоторых других факторов, бокс может иметь:

  • Вход под сим-карту — некоторые приставки имеют 3G модуль, и через симку пользователь сможет выйти в интернет без Ethernet кабеля. Кроме того, на симку могут приходить сообщения от оператора, и API платформ позволяет работать с СМС сообщениями.
  • Вход для сигнала (спутниковый/кабельный вход) — если приставка спутниковая или кабельная, он необходим для приема цифрового вещания (проще говоря, чтобы можно было подключиться к потокам ТВ каналов). Помимо вещания через кабель может прийти служебная информация.
  • Вход под смарт-карту — опишу это чуть ниже.
  • Разъем под Wi-Fi антенну — некоторые боксы могут работать с Wi-Fi сетями.


Вот так это может выглядеть (фотки из сети, для примера):

image

image

Причем здесь JavaScript?


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

Этот портал — ничто иное, как одностраничное приложение (SPA — Single Page Application) написанное на JavaScript, и открытое во вкладке браузера запущенного на приставке.

Когда мы включаем бокс (по питанию) в общем случае происходит следующее (все лишнее не описываю):

  1. Запустилась ось приставки
  2. Приставка запускает браузер, и открывает в нем HTML файл


Здесь есть свои особенности:

  • На некоторых приставках файл конфигурации доступен для записи — можно, например, изменить путь до HTML файла, который будет открываться во вкладке браузера при старте или рестарте браузера. В целом, многие настройки используются для оптимизации процесса отладки кода, не более.
  • На некоторых приставках запускается не HTML файл вашего портала, а собственный портал приставки, в котором вы при помощи пульта вводите адрес файла (либо адрес вашего сервера, который раздает исходники), и затем браузер просто открывает ссылку которую вы ввели.


Добавлено от rule:
Не все приставки позволяют менять страницу портала или адрес портала. Например Amino на первой вашей странице обязывает иметь специально ключи для этого т производителя. Есть несколько уровней доступа для этого.


Получается, что почти никаких навыков для разработки портала на приставке не нужно? Достаточно лишь настроить приставку, и научиться деплоить на нее свое приложение? — это не совсем так.

Приставка — это платформа с очень низкой производительностью, и поэтому разработка под веб, и под бокс, это совершенно разные уровни сложности. Именно поэтому почти любая ошибка кодирования дает о себе знать — ваше приложение будет неверно рендериться, рендериться «лесенкой», тормозить, отказываться работать, «валить» браузер, выдавать артефакты, выедать память, и многое-многое другое. Об этом я расскажу чуть позже.

Зачем нужна приставка?


  • Я абонент — я хочу держать на стене плазму, подключить к ней приставку, и смотреть фильмы, спутниковое ТВ в высоком качестве, узнавать будут ли утром пробки когда я поеду на работу, и не прикладывать никаких усилий.
  • Я оператор связи — я могу продавать (или, например, давать в аренду) своим абонентам приставки, и через нее продавать услуги (продажа фильмов, пакетов каналов, другое) и получать прибыль.


Соответственно, подавляющее большинство порталов на приставке направлено на решение одной большой задачи — с одной стороны создать возможность продажи услуг (продажа фильмов, просмотр платных каналов и многое другое), а с другой стороны сделать максимально удобное приложение интегрированное с другими сервисами (карта, почта, социальные сети, новости, SMS, серфинг в интернете и другое), позволяющее смотреть ТВ и решать множество других задач в одной «коробке».

Если это обычный браузер, разве мы сможем все это реализовать? Телевидение? Фильмы? SMS? — сможем, потому что приставка это не просто коробка с браузером внутри. Каждый бокс предлагает собственное JavaScript API.

JavaScript API приставки


В общем случае API приставки можно разделить на группы:

  • API плеера приставки — методы чтобы управлять воспроизведением.
  • API для получения информации о текущем потоке — субтитры, дорожки аудио, телетекст, другое...
  • API для работы с входами приставки — проверка наличия HDMI, Ethernet кабеля, спутникового кабеля, наличие 3G, другое...
  • API для проверки наличия соединения — наличие интернета во вставленном кабеле, наличие или качество спутникового сигнала, другое...
  • API для работы с хранилищем приставки — не на всех боксах, но довольно часто локальное хранилище браузера очищается после рестарта приставки, поэтому для сохранения данных между перезагрузками используется отдельный API.
  • API для получения данных — получение IP бокса, MAC-адреса, модель бокса, и другое..
  • API для работы с сетью вещания — сканирование каналов, другое.
  • API для настройки бокса — формат увеличения изображения, пропорции изображения, другое..
  • API для работы с файлами и файловой системой — получить длительность файла, получить список файлов на флешке, узнать кодек видео, другое...


Этого более чем достаточно для решения большинства задач.

Как пользователь взаимодействует с порталом?


К каждой приставке в комплекте идет пульт управления. Обычно он содержит кнопки для решения основных задач связанных с ТВ:

  • Кнопки навигации — «Вверх», «Вправо», «Вниз», «Влево», «Ввод», «Меню», «Назад».
  • Кнопки управления громкостью — «Сделать громче», «Сделать тише», «Выключить звук»
  • Кнопки для переключения каналов — «Следующий канал», «Предыдущий канал»
  • Кнопки управления воспроизведением — «Плей», «Стоп», «Пауза», «Мотать вперед», «Мотать назад», «Начать запись». В зависимости от производителя какие-то кнопки могут отсутствовать или быть совмещенными.
  • Цифровая клавиатура — цифры и нарисованные на них буквы. Нужны для упрощения ввода символов,
  • Цветные кнопки — для упрощения взаимодействия со страницами. На эти кнопки вешается какая-то логика в зависимости от состояния текущей страницы.
  • Включить/Выключить
  • Другие кастомные кнопки — кнопки ведущие на конкретные страницы приложения, доп. управление навигацией, и другое.


Как портал взаимодействует с пультом?

Разрабатывая приложение нужно поймать нажатие кнопки и обработать его. Здесь все довольно просто — нажатие кнопки на пульте обрабатывается как обычное нажатие на клавишу клавиатуры. Одно отличие — коды клавиш для каждого вендора свои.

Bonus-track — на некоторых боксах события «keyup» и «keydown» приходят одновременно. Поэтому, если захотите сделать обработку зажатия клавиши пульта (такие кейсы бывают), вспомните про картинку костыли_и_велосипеды.jpg

Что мы имеем?


Подведем небольшой промежуточный итог этой быстрой вводной:

  • Бокс — слабая машина на базе Linux
  • Бокс при включении запускает браузер, и поэтому приложение на приставке — это веб-приложение по своей сути.
  • Работа с боксом происходит через SSH или Telnet.
  • Бокс предоставляет API доступное из браузера для решения широкого круга задач связанных с ТВ, аудио/видео файлами, и многим другим.


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

Звучит хорошо? — звучит отлично! Однако, на практике все не так хорошо звучит, и сейчас мы переходим к более интересной, второй части статьи: Заметки

Заметки


Повторюсь — приставка это компьютер с распиленным Linux, и браузером в который вкручен дополнительный API, благодаря которому большинство из задач стоящих перед порталом на приставке становятся реализуемыми.

Для нас важна лишь вторая часть этого высказывания — производители боксов допиливают браузеры!

В боксах бывают установлены различные браузеры, но чаще всего встречаются Opera или браузеры на WebKit. В результате допила браузеры начинают обладать самыми различными багами: утечки памяти в самых неожиданных местах, частично неработающий сборщик мусора, падение браузера в результате самого обычного вызова метода, баги отрисовки, и многое другое.

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

Поехали..

Операции с DOM


Операции с DOM — самые тяжелые операции. На приставке это очень (!) заметно (в прямом смысле).

Если количество операций с DOM не сведено к минимуму, тогда есть вероятность:

  • Получить очень неприятный эффектвы будете видеть (буквально) как отрисовывается страница. Фактически, это Composite Layers, который отрабатывает очень медленно, и поэтому перерисовку грида страницы видно невооруженным глазом (заменяется один сектор сетки за другим, а не все сразу).
  • Затратить много времени на рендер страницы.


Основная вытекающая из этого проблема — существенно портится UX. Я как пользователь хочу нажать кнопку, и увидеть мгновенно открывшуюся страницу, без месива из перерисовываемых слоев и ожидания в 1-3 секунды. Если я буду видеть это постоянно — у меня появятся неприятные ощущения от взаимодействия с порталом. Я как пользователь прежде всего хочу испытывать удовольствие от взаимодействия с приложением, и думать что потратил свои деньги не зря.

Копнем немного поглубже — Что конкретно нужно минизировать?

Нужно минимизировать или исключить:

  • Вставку элементов пачками — давайте дружить с document.createDocumentFragment().
  • Изменение стиля элементов — если есть возможность спроектировать страницу таким образом, чтобы в каком-то конкретном кейсе (например, перемещение элементов) вы смогли изменить стиль одного или двух элементов вместо целой пачки элементов, нужно ее использовать.
  • Layout + перерисовку дерева элементов. Для понимания о чем идет речь я приведу пример. Например, у вас есть 3 слоя (div), расположенных друг рядом с другом. Если вы добавите первому из них границу в 1px, тогда перерисованы будут все слои вместо одного. Эту лишнюю нагрузку можно исключить спроектировав страницу по-другому.
  • Изменение размеров изображения — если взять изображение размером 100x100, и разместить его задав ему размер 90x90, это будет лишней нагрузкой на браузер (браузер будет ужимать изображение). Если вы делаете каталог с плиткой, где каждый элемент содержит изображение, это будет лишней нагрузкой. Если есть возможность, вытягивайте с сервера изображения строго необходимого вам размера, и не перегружайте браузер лишними в данном случае действиями.
  • Анимации. Приставка может вам позволить добавить анимацию в приложение, но только легковесную анимацию (прокрутка небольшого списка, меню, прокрутка текста). В остальных случаях приставке не хватит производительности, и анимация будет проходить рывками. Об анимации больших элементов страницы можно и вовсе забыть. Есть два исключения — канвас и CSS3 трансформации. Они работают более-менее (не тормозят существенно, но и не «60fps». Назовем это — терпимо), но это дополнительная сложность в разработке.


Резюмируем. Рецепты при работе с DOM:

  • Используйте document.createDocumentFragment — одна операция с DOM намного эффективнее чем несколько (капитан очевидность снова с вами).
  • Проектируйте страницу с расчетом на минимальное количество модификаций DOM при взаимодействии со страницей.
  • Используйте верстку с абсолютно расположенными элементами.
  • Не используйте изображения, которые не подходят вам по размеру.
  • Стремитесь исключить лишнюю нагрузку на браузер.
  • Стремитесь не использовать прозрачность — это заставляет браузер делать больше расчетов.
  • Откажитесь от анимаций, или используйте канвас.


CSS


Без лишней воды, рецепты по оптимизации таблиц стилей, и взаимодействию с классами:

  • Старайтесь не использовать вложенность более одного уровня — это нагрузка на браузер. Если сделать большую вложенность, при изменении разметки, классов элемента или стилей элемента, браузер будет обходить намного больше узлов с целью генерации стиля элемента, нежели с минимальной вложенностью.
  • Не используйте тяжелые селекторы.
  • Если необходимо произвести несколько операций (изменение стиля элемента), которые нельзя объединить — делайте их вместе, подряд. Браузер это определяет, и не перерисовывает (в том числе не производит перерасчёт стилей) элементы лишние n-раз.


Как следствие — использование CSS фреймворков (например, Bootstrap) нежелательно.

Есть отличное решение, которое дает мощный прирост производительности — постараться отказаться от классов, и генерировать верстку с inline-стилями (тег style). Возможно, есть даже плагины для Gulp/Grunt.

Немного про поддержку CSS свойств. В большинстве боксов стоит WebKit, и многое из CSS3 поддерживается. Если вы разрабатываете приложение не под один бокс, а сразу под несколько, тогда не рекомендую использовать различные новые «плюшки». Не исключено, что на одной платформе они отработают отлично, а на второй вам не прилетят баги.

Добавим конкретики. Что часто поддерживается (из CSS3; список очень неполный, составил исходя из реальных кейсов, по памяти):

  • border-radius
  • rgba
  • linear-gradient
  • text-overflow
  • background-size
  • Трансформации
  • Анимации
  • opacity
  • box-shadow
  • overflow-x
  • overflow-y
  • line-break
  • word-wrap
  • text-shadow
  • @font-face
  • box-sizing
  • text-overflow


Баги


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

Какие бывают баги?

Чаще всего встречаются баги связанные с отрисовкой страницы: не отрисовался фон div'а, не выгрузился старый фон при перерисовке элемента, при отрисовке прозрачной границы браузер игнорирует все слои находящиеся под ней (видно сразу фон страницы), и многие другие баги.

Реже встречаются баги в движке: вызов нативного метода валит браузер, if в особых условиях валит браузер, итерация по ключам объекта происходит в не отсортированном виде (возможно, не баг не баг: от gibson_dev «В том то и весь цимес что оно по спецификации так и есть, в сортированном виде только массивы, а конструкция for..in этого не гарантирует»), и другие еще более редкие кейсы.

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

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

Утечки памяти


Утечка памяти на приставке может быть из «ниоткуда». Без примеров, потому что универсального рецепта как это обойти нет.

Правило простоепериодически прогоняйте ваше приложение на утечки памяти. Если утечки есть — ищем откуда, и закрываем «течь».

Другое


Как обычно деплоится приложение (при разработке)?


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

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

Скрытый текст
Способ #1 — Через флешку

  1. Собираем наше приложение
  2. Копируем исходники на флешку
  3. Вставляем флешку в бокс
  4. Заходим на приставку через telnet или ssh (в зависимости от бокса)
  5. Заменяем исходники в директории, из которой приставка пытается запустить HTML файл (обычно это файл index.html)


Способ #2 — Выкачиваем исходники со своей машины

  1. Разворачиваем сервер (например, на express'е), который раздает статику из директории в которую собирается ваше приложение
  2. Собираем приложение
  3. Архивируем приложение
  4. Заходим на приставку через telnet или ssh (в зависимости от бокса)
  5. Выкачиваем исходники с нашей машины (wget, curl)
  6. Заменяем исходники в директории, из которой приставка пытается запустить HTML файл (обычно это файл index.html)


Я думаю что самый лучший способ — способ #3.

Способ #3 — Без деплоя
Этот способ будет работать, если вы можете указать приставке откуда ей тянуть HTML файл (почти на всех боксах это возможно).

  1. Разворачиваем сервер (например, на express'е), который раздает статику из директории в которую собирается ваше приложение
  2. Заходим на приставку через telnet или ssh (в зависимости от бокса)
  3. Редактируем конфиг бокса — указываем адрес HTML файла на вашем локальном сервере


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



Смарт-карта


В боксах может быть смарт-карта. Я не специалист в этой области, поэтому читаем об этом в википедии.

В боксе она может присутствовать в двух видах:

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


Больше ничего об этом не напишу — не специалист, и понимаю как это работает только на уровне «потрогал-пощупал». Не хочу вам случайно соврать.

Финишируем


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

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

P.S

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

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

Будет отлично, если будут дополнения к этой статье — пишите в комментариях, я добавлю всю полезную информацию в текст статьи.
Теги:javascriptодноплатные компьютеры
Хабы: JavaScript Клиентская оптимизация
+10
29,5k 51
Комментарии 22
Лучшие публикации за сутки