setTimeout 0 как лекарство против синхронной природы JavaScript 14.05.2015

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

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

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

Лекарство против данной проблемы оказалось достаточно простым и представляло собой вызов нативного метода перемотки при помощи setTimeout(function () {….}, 0). При таком подходе вызов метода перемотки становился в ту же очередь на исполнение что и события от нативного плеера, и, таким образом, все накопленные за время синхронного исполнения кода события должны быть обработаны до вызова метода перемотки.

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

P.S. Решение с подпиской на нативное событие в данном конкретном случае оказалось не совсем удачным. Более надежным решением был бы непосредственный запрос текущей позиции плеера.

by 14.05.2015