Перейти к основному содержимому

Релиз V8 версии v6.6

· 7 мин. чтения
Команда V8

Каждые шесть недель мы создаем новую ветку V8 в рамках нашего процесса релизов. Каждая версия формируется из основной ветки V8 перед бета-этапом Chrome. Сегодня мы рады объявить о нашей новой ветке, V8 версии 6.6, которая будет находиться в бета-версии до выпуска одновременно со стабильной версией Chrome 66 через несколько недель. V8 v6.6 наполнен множеством полезностей для разработчиков. Этот пост предоставляет предварительный обзор некоторых из интересных моментов перед релизом.

Программные возможности языка JavaScript

Ревизия Function.prototype.toString #function-tostring

Function.prototype.toString() теперь возвращает точные фрагменты исходного кода, включая пробелы и комментарии. Вот пример сравнения старого и нового поведения:

// Обратите внимание на комментарий между ключевым словом `function`
// и именем функции, а также пробелом после имени функции.
function /* комментарий */ foo () {}

// Ранее:
foo.toString();
// → 'function foo() {}'
// ^ комментарий отсутствует
// ^ пробел отсутствует

// Теперь:
foo.toString();
// → 'function /* comment */ foo () {}'

JSON ⊂ ECMAScript

Символы разделителя строк (U+2028) и разделителя абзацев (U+2029) теперь разрешены в строковых литералах, соответствующих JSON. Ранее эти символы считались разделителями строк в строковых литералах, и их использование приводило к исключению SyntaxError.

Необязательный параметр в catch

Блок catch в выражениях try теперь может использоваться без параметра. Это полезно, если объект exception не требуется для обработки исключения.

try {
doSomethingThatMightThrow();
} catch { // → Смотрите, мама, без параметра!
handleException();
}

Односторонняя обрезка строк

В дополнение к String.prototype.trim(), V8 теперь реализует String.prototype.trimStart() и String.prototype.trimEnd(). Эта функциональность ранее была доступна через нестандартные методы trimLeft() и trimRight(), которые остаются доступными как синонимы новых методов для обеспечения обратной совместимости.

const string = '  hello world  ';
string.trimStart();
// → 'hello world '
string.trimEnd();
// → ' hello world'
string.trim();
// → 'hello world'

Array.prototype.values

Метод Array.prototype.values() предоставляет массивам тот же интерфейс итерации, что и коллекции ES2015 Map и Set: все они теперь могут быть перебраны с использованием методов keys, values или entries. Это изменение потенциально несовместимо с существующим JavaScript-кодом. Если вы обнаружите странное или сломанное поведение на сайте, попробуйте отключить эту функцию через chrome://flags/#enable-array-prototype-values и создать отчет о проблеме.

Кэширование кода после выполнения

Термины холодная и теплая загрузка могут быть хорошо известны людям, интересующимся производительностью загрузки. В V8 также существует концепция горячей загрузки. Давайте объясним разные уровни на примере Chrome, внедряющего V8:

  • Холодная загрузка: Chrome впервые видит посещаемую веб-страницу и не имеет вообще никаких кешированных данных.
  • Теплая загрузка: Chrome запоминает, что веб-страница уже была посещена, и может извлекать определенные ресурсы (например, изображения и исходные файлы скриптов) из кеша. V8 распознает, что страница уже предоставила этот файл скрипта, и, соответственно, кэширует скомпилированный код вместе с файлом скрипта в дисковом кеше.
  • Горячая загрузка: При третьем посещении веб-страницы Chrome, предоставляя файл скрипта из дискового кеша, также предоставляет V8 кэшированный ранее код. V8 может использовать этот кэшированный код, чтобы избежать необходимости заново парсить и компилировать скрипт.

До версии V8 v6.6 мы кэшировали сгенерированный код сразу после компиляции верхнего уровня. V8 компилирует только те функции, которые сразу используются во время компиляции верхнего уровня и отмечает остальные функции для ленивой компиляции. Это означало, что кэшированный код содержал только код верхнего уровня, а все остальные функции приходилось лениво компилировать с нуля при каждой загрузке страницы. Начиная с версии 6.6, V8 кэширует код, сгенерированный после выполнения скрипта на верхнем уровне. По мере выполнения скрипта все больше функций лениво компилируется и могут быть включены в кэш. Таким образом, эти функции больше не нужно компилировать при последующих загрузках страницы, что сокращает время компиляции и анализа в сценариях горячей загрузки на 20–60%. Видимое изменение для пользователя — менее загруженный главный поток, что обеспечивает более плавный и быстрый опыт загрузки.

Скоро ожидайте подробный блог о этой теме.

Компиляция в фоне

V8 уже некоторое время может анализировать код JavaScript на фоне. С новым байт-кодовым интерпретатором Ignition, выпущенным в прошлом году, мы смогли расширить эту поддержку, чтобы также позволить компиляцию исходного кода JavaScript в байт-код на фоновой нити. Это позволяет встраиваемым программам выполнять больше работы вне главного потока, освобождая его для выполнения большего объема JavaScript и уменьшения задержки. Мы включили эту функцию в Chrome 66, где наблюдается сокращение времени компиляции на главном потоке от 5% до 20% на типичных веб-страницах. Для получения подробностей, пожалуйста, ознакомьтесь с последним блогом о этой функции.

Удаление нумерации AST

Мы продолжаем получать преимущества от упрощения нашего конвейера компиляции после запуска Ignition и TurboFan в прошлом году. Наш предыдущий конвейер требовал этапа пост-анализа, называемого "нумерация AST", где узлам в созданном абстрактном синтаксическом дереве присваивались номера, чтобы различные компиляторы, использующие его, имели общий ориентир.

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

С новым конвейером байт-код Ignition стал общим ориентиром, и сама нумерация больше не была необходима — однако оставшаяся функциональность всё ещё требовалась, и этап нумерации AST оставался.

В V8 v6.6 нам, наконец, удалось переместить или устаревить эту оставшуюся функциональность в другие этапы, что позволило нам удалить обход дерева. Это привело к улучшению времени компиляции на 3-5% в реальном мире.

Улучшения производительности асинхронных операций

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

Улучшения производительности Promises

Кроме того, производительность асинхронных генераторов и асинхронной итерации была значительно улучшена, что делает их жизнеспособным вариантом для предстоящей Node 10 LTS, запланированной с V8 v6.6. Например, рассмотрим следующую реализацию последовательности Фибоначчи:

async function* fibonacciSequence() {
for (let a = 0, b = 1;;) {
yield a;
const c = a + b;
a = b;
b = c;
}
}

async function fibonacci(id, n) {
for await (const value of fibonacciSequence()) {
if (n-- === 0) return value;
}
}

Мы измерили следующие улучшения для этого паттерна до и после транспиляции Babel:

!Улучшения производительности асинхронных генераторов](/_img/v8-release-66/async-generator.svg)

Наконец, улучшения байт-кода для "приостановимых функций", таких как генераторы, асинхронные функции и модули, улучшили производительность этих функций при работе в интерпретаторе и уменьшили их размер после компиляции. Мы планируем еще больше улучшить производительность асинхронных функций и асинхронных генераторов в будущих версиях, так что следите за обновлениями.

Улучшения производительности массивов

Производительность Array#reduce была увеличена более чем в 10 раз для дырявых массивов с двойной точностью (см. наш блог-пост с объяснением, что такое дырявые и упакованные массивы). Это расширяет быстрое выполнение для случаев, когда Array#reduce применяется к дырявым и упакованным массивам с двойной точностью.

Улучшения производительности Array.prototype.reduce

Меры защиты от ненадежного кода

В V8 v6.6 мы внедрили дополнительные меры защиты от уязвимостей боковых каналов, чтобы предотвратить утечку информации в ненадежный JavaScript и WebAssembly код.

Удаление GYP

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

Профилирование памяти

DevTools Chrome теперь могут отслеживать и сохранять снимки объектов DOM на C++ и отображать все достижимые объекты DOM из JavaScript с их ссылками. Эта функция является одним из преимуществ нового механизма отслеживания C++ в сборщике мусора V8. Для получения дополнительной информации, ознакомьтесь с посвященным блог-постом.

API V8

Пожалуйста, используйте git log branch-heads/6.5..branch-heads/6.6 include/v8.h, чтобы получить список изменений API.