Более быстрые и функциональные API интернационализации
Спецификация API интернационализации ECMAScript (ECMA-402, или Intl
) предоставляет ключевые функции, зависящие от локали, такие как форматирование дат, чисел, выбор формы множественного числа и сортировка. Команды Chrome V8 и Google Internationalization работали над добавлением новых функций в реализацию ECMA-402 в V8, при этом устраняя технические долги и улучшая производительность и совместимость с другими браузерами.
Улучшения архитектуры
Изначально спецификация ECMA-402 была реализована в основном на JavaScript с использованием расширений V8 и находилась вне кода V8. Использование внешнего API Extension означало, что несколько внутренних API V8, используемых для проверки типов, управления временем жизни внешних объектов C++ и внутреннего хранения приватных данных, не могли быть использованы. В рамках повышения производительности запуска эта реализация позже была перемещена в кодовую базу V8 для включения снапшотов этих встроенных функций.
V8 использует специализированные JSObject
с настраиваемыми формами (скрытые классы) для описания встроенных объектов JavaScript, указанных в ECMAScript (например, Promise
, Map
, Set
и т.д.). Такой подход позволяет V8 заранее выделить необходимое количество внутренних слотов и обеспечить быстрый доступ к ним, вместо роста объекта по одному свойству, что приводит к снижению производительности и увеличению использования памяти.
Реализация Intl
не была построена на такой архитектуре в силу исторического разделения. Вместо этого все встроенные объекты JavaScript, указанные в спецификации интернационализации (такие как NumberFormat
, DateTimeFormat
), были общими JSObject
, которые должны были переходить через несколько добавлений свойств для своих внутренних слотов.
Другим недостатком отсутствия специализированных JSObject
заключалось в усложнении проверки типов. Информация о типах хранилась под приватным символом и проверялась как на стороне JS, так и на стороне C++ с использованием затратного доступа к свойствам, вместо простого обращения к их форме.
Обновление кода
С учетом текущего отхода от написания встроенных функций в V8, было логично использовать эту возможность для модернизации реализации ECMA402.
Уход от самохостинга JS
Хотя самохостинг обеспечивает лаконичный и читаемый код, частое использование медленных вызовов времени выполнения для доступа к API ICU вызывало проблемы с производительностью. В результате некоторая функциональность ICU была дублирована в JavaScript для сокращения числа таких вызовов.
Переписав встроенные функции на C++, мы добились гораздо более быстрого доступа к API ICU, так как больше не существует накладных расходов на вызовы времени выполнения.
Улучшение ICU
ICU — это набор библиотек C/C++, используемый множеством приложений, включая все основные движки JavaScript, для поддержки Unicode и глобализации. В процессе перехода реализации Intl
на ICU в V8 мы обнаружили и исправили несколько ошибок ICU.
В процессе внедрения новых предложений, таких как Intl.RelativeTimeFormat
, Intl.ListFormat
и Intl.Locale
, мы расширили ICU, добавив несколько новых API для поддержки этих новых предложений ECMAScript.
Все эти дополнения помогают другим движкам JavaScript быстрее внедрять эти предложения, ускоряя развитие веба! Например, в Firefox в настоящее время идет разработка нескольких новых API Intl
на основе нашей работы с ICU.
Производительность
В результате этой работы мы повысили производительность API интернационализации, оптимизировав несколько быстрых путей и кэшируя инициализацию различных объектов Intl
и методов toLocaleString
у Number.prototype
, Date.prototype
и String.prototype
.
Например, создание нового объекта Intl.NumberFormat
стало примерно в 24 раза быстрее.
Обратите внимание, что для повышения производительности рекомендуется явно создавать и повторно использовать объект Intl.NumberFormat
, Intl.DateTimeFormat
или Intl.Collator
, а не вызывать методы, такие как toLocaleString
или localeCompare
.
Новые функции Intl
Вся эта работа обеспечила отличную основу для разработки новых функций, и мы продолжаем внедрять все новые предложения по интернационализации, которые находятся на этапе 3.
Intl.RelativeTimeFormat
был выпущен в Chrome 71, Intl.ListFormat
был выпущен в Chrome 72, Intl.Locale
был выпущен в Chrome 74, а dateStyle
и timeStyle
опции для Intl.DateTimeFormat
и поддержка BigInt для Intl.DateTimeFormat
выпущены в Chrome 76. Intl.DateTimeFormat#formatRange
, Intl.Segmenter
, и дополнительные опции для Intl.NumberFormat
в настоящее время разрабатываются в V8, и мы надеемся, что они скоро будут внедрены!
Многие из этих новых API, а также другие, находящиеся на дальнейших этапах разработки, стали возможны благодаря нашей работе по стандартизации новых функций для помощи разработчикам в интернационализации. Intl.DisplayNames
— это предложение на этапе 1, которое позволяет пользователям локализовать отображение имен языков, регионов или скриптовых имен. Intl.DateTimeFormat#formatRange
— это предложение на этапе 3, которое определяет способ форматирования диапазонов дат в краткой форме с учетом локализации. Унифицированное предложение API Intl.NumberFormat
— это предложение на этапе 3, которое улучшает Intl.NumberFormat
путем добавления поддержки единиц измерений, валют и политик отображения знаков, а также научной и компактной нотации. Вы также можете участвовать в разработке ECMA-402, внося вклад в его репозиторий на GitHub.
Заключение
Intl
предоставляет насыщенный функциями API для выполнения нескольких операций, необходимых для интернационализации вашего веб-приложения, оставляя всю трудоемкую работу браузеру, без необходимости передачи большого объема данных или кода по сети. Продуманное использование этих API может сделать ваш пользовательский интерфейс более эффективным в разных локалях. Благодаря работе команд Google V8 и i18n в сотрудничестве с TC39 и его подгруппой ECMA-402, вы теперь можете получить доступ к большему количеству функций с повышенной производительностью и ждать дальнейших улучшений со временем.