Cloudflare, Mozilla и Facebook развивают BinaryAST для ускорения загрузки JavaScript

Инженеры из компаний Cloudflare, Mozilla, Facebook и Bloomberg предложили новый формат BinaryAST для ускорения доставки и обработки JavaScript-кода при открытии сайтов в браузере. BinaryAST выносит фазу синтаксического разбора на сторону сервера и поставляет уже сформированное абстрактное синтаксическое дерево (AST). При получении BinaryAST браузер сразу может перейти на стадию компиляции, минуя парсинг исходного кода JavaScript.

Для тестирования подготовлена эталонная реализация, поставляемая под лицензий MIT. Для парсинга используются компоненты Node.js, а код для оптимизации и формирования AST написан на языке Rust. На стороне браузера поддержка BinaryAST уже доступна в ночных сборках Firefox. Кодировщик в BinaryAST может применяться как на уровне инструментария конечного сайта, так и для упаковки скриптов внешних сайтов на стороне прокси или сети доставки контента. В настоящее время уже начался процесс стандартизации BinaryAST рабочей группой ECMA TC39, после завершения которого формат сможет сосуществовать с существующими методами сжатия отдаваемого контента, такими как gzip и brotli.

0_1558111216.png 0_1558111236.png

Значительное время при обработке JavaScript занимает фаза загрузки и синтаксического разбора кода. С учётом того, что объём загружаемого JavaScript на многих популярных сайтах приближается к 10 Мб (например для LinkedIn — 7.2 Мб, Facebook — 7.1 Мб), первичная обработка JavaScript вносит существенную задержку. Стадия парсинга на стороне браузера также замедляется из-за невозможности полноценного построения AST на лету по мере загрузки кода (браузеру приходится ожидать завершения загрузки блоков, например конца функций, для получения недостающей для разбора текущих элементов информации).

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

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

BinaryAST позволяет вписаться в текущую модель разработки и доставки кода без создания нового формата байткода и без изменения языка JavaScript. Размер данных в формате BinaryAST сопоставим со сжатым минифицированным JavaScript-кодом, а скорость обработки за счёт исключения фазы парсинга исходных текстов заметно увеличивается. Также формат BinaryAST позволяет выполнять компиляцию в байткод по мере загрузки, не ожидая завершения получения всех данных. Более того, парсинг на стороне сервера позволяет исключить из отдаваемого представления BinaryAST неиспользуемые функции и лишний код, на который при парсинге на стороне браузера тратится время, как на разбор, так и на передачу лишнего трафика.

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

Тесты кода facebook.com показали, что на разбор JavaScript тратится 10–15% ресурсов CPU и на парсинг уходит больше времени, чем на генерацию байткода и начальное формирование кода для JIT. В движке SpiderMonkey время полного построения AST занимает 500–800 мс и применение BinaryAST позволило сократить этот показатель на 70–90%. В целом, для большинства web-феймвроков при применении BinaryAST время парсинга JavaScript сокращается на 3–10% в режиме без оптимизации и на 90–97% при включении режима игнорирования неиспользуемых функций. При выполнении тестового JavaScript-набора, размером 1.2 Мб, применение BinaryAST позволило ускорить время начала запуска с 338 до 314 мс на настольной системе (Intel i7) и с 2019 до 1455 мс на мобильном устройстве (HTC One M8).

©  OpenNet