Быстрая работа JavaScript - ключ к отзывчивому веб-приложению. Несмотря на продвинутые оптимизации, используемые V8, парсинг и компиляция критического JavaScript кода во время запуска приложения, все еще могут создавать бутылочные горлышки в плане перфоманса. Знание же о том, какие JS функции должны быть скомпилированы в процессе первичной компиляции, может ускорить загрузку веб-страницы.
Исполняя загруженный из сети скрипт, V8 должен принять решение для каждой функции: компилировать ее немедленно (“жадно”) или отложить этот процесс. Если функция, которая не была скомпилирована, позже вызывается, V8 должен скомпилировать ее “по требованию” (on demand - в оригинале).
Если функция JavaScript вызывается во время загрузки страницы, ее немедленная компиляция полезна, потому что:
-
В течение первичной обработки скрипта мы должны по крайней мере произвести поверхностный парсинг, чтобы найти окончание функции. В JS поиск окончания функции требует парсинга всего синтаксиса (нет никаких сокращений, где мы могли бы посчитать фигурные скобки — грамматика слишком сложна). Первичный парсинг вначале и последующий полный парсинг - это двойная работа.
-
Если мы компилируем функцию “жадно”, это происходит в фоновом режиме, и чередуясь с загрузкой скрипта из сети. Если вместо этого мы компилируем функцию только во время ее вызова, то будет слишком поздно распараллеливать работу, поскольку основной поток не сможет продолжить работу, пока функция не будет скомпилирована.
Подробнее о том, как V8 парсит и компилирует JavaScript, можно почитать здесь.
Многие веб-страницы выиграли бы от выбора правильных функций для жадной компиляции. Например, в эксперименте с популярными веб-страницами 17 из 20 показали улучшения, а среднее сокращение времени анализа и компиляции составило 630 мс.
Команда V8 разрабатывает фичу под названием Явное Указание Компилятору (Explicit Compile Hints), которая позволит веб-разработчикам контролировать, какие файлы или функции должны быть скомпилированы “жадно”. Браузер Chrome версии от 136 уже сейчас поддерживает версию Явного Указания Компилятору, в которой вы можете выбрать отдельные файлы для “жадной” компиляции.
Эта версия особенно полезна, если у вас есть «основной файл», который вы можете выбрать для быстрой компиляции, или если вы можете перемещать код между исходными файлами для создания такого основного файла.
Вы можете запустить “жадную” компиляцию для всего файла, вставив такой магический комментарий
//# allFunctionsCalledOnLoad
в самое начало файла.
Однако эту функцию следует использовать с осторожностью — компиляция слишком больших файлов будет расходовать много времени и памяти!
Убедитесь сами - явные указания в действии
Вы можете увидеть работу подсказок компиляции, логируя события функции. Берем файл index.html
и вставляем следующие скрипты:
<script src="script1.js"></script>
<script src="script2.js"></script>
script1.js:
function testfunc1() {
console.log('testfunc1 called!');
}
testfunc1();
script2.js:
//# allFunctionsCalledOnLoad
function testfunc2() {
console.log('testfunc2 called!');
}
testfunc2();
Не забудьте запустить Chrome с чистым каталогом пользовательских данных, чтобы кэширование кода не испортило ваш эксперимент. Пример командной строки:
rm -rf /tmp/chromedata && google-chrome --no-first-run --user-data-dir=/tmp/chromedata --js-flags=--log-function_events > log.txt
После перехода на тестовую страницу вы можете увидеть в журнале следующие события функций:
$ grep testfunc log.txt
function,preparse-no-resolution,5,18,60,0.036,179993,testfunc1
function,full-parse,5,18,60,0.003,181178,testfunc1
function,parse-function,5,18,60,0.014,181186,testfunc1
function,interpreter,5,18,60,0.005,181205,testfunc1
function,full-parse,6,48,90,0.005,184024,testfunc2
function,interpreter,6,48,90,0.005,184822,testfunc2
Поскольку testfunc1 был скомпилирован лениво, мы видим событие parse-function, когда он в конечном итоге вызывается:
function,parse-function,5,18,60,0.014,181186,testfunc1
Для testfunc2 мы не видим соответствующего события, поскольку подсказка компиляции заставила его проанализировать и скомпилировать “жадно”.
Будущее явных указаний компилятору
В долгосрочной перспективе разработчики V8 хотят перейти к выбору отдельных функций для “жадной” компиляции. Это позволит веб-разработчикам контролировать, какие именно функции они хотят компилировать сразу, и выжимать последние биты производительности для оптимизации своих веб-страниц.