メインコンテンツまでスキップ

より高速で多機能な国際化API

· 約7分
[சத்யா குணசேகரன் (Sathya Gunasekaran)](https://twitter.com/_gsathya)

ECMAScript国際化APIの仕様書 (ECMA-402、またはIntl) は、日付フォーマット、数値フォーマット、複数形選択、並べ替えなどのロケール固有の重要な機能を提供します。Chrome V8とGoogle国際化チームは、V8のECMA-402の実装に機能を追加しつつ、技術的負債を整理し、パフォーマンスや他のブラウザとの互換性を向上させる取り組みを行っています。

基本的なアーキテクチャ改善

当初、ECMA-402仕様は主にV8拡張を使用しJavaScriptで実装され、V8コーディングベースの外部に存在していました。外部拡張APIの使用は、型チェック、外部C++オブジェクトのライフタイム管理、内部プライベートデータのストレージに関するV8の内部API利用を制限しました。スタートアップ性能を改善する一環として、この実装は後にV8コードベースに移動され、これらのビルトインのスナップショット作成が可能になりました。

V8は専門化されたJSObjectを使用し、ECMAScriptで指定されたJavaScriptのビルトインオブジェクト(PromiseMapSetなど)を記述するためのカスタムシェイプ(隠しクラス)を持っています。この方法を活用することで、必要な内部スロット数を事前に割り当て、高速なアクセスを生成できます。この結果物件を段階的に1つずつ追加する必要が無くなり、性能が向上しメモリ使用が改善されます。

Intlの実装は、歴史的な分離の影響でこのようなアーキテクチャに基づいていませんでした。その結果、国際化仕様で指定されるビルトインJavaScriptオブジェクト(NumberFormatDateTimeFormatなど)は、一般的なJSObjectとされ、内部スロットのいくつかのプロパティ追加の処理が必要でした。

専門化されたJSObjectが欠けているもう1つの影響として、型チェックがより複雑になりました。型情報はプライベートシンボルの下に保存され、費用がかかるプロパティアクセスで型チェックがJS側とC++側で行われました。専用のシェイプを見るよりも効率的ではありませんでした。

コードベースの近代化

現在、V8でのセルフホストビルトインの記述から遠ざかる動きの中で、ECMA402実装を近代化する良い機会となりました。

セルフホストJSからの移行

セルフホスティングは簡潔で読み取りやすいコードを提供しますが、ICU APIへのアクセスのための遅いランタイム呼び出しが頻繁に使用されることで、性能の問題が生じました。この結果、多くのICU機能がJavaScriptで複製され、ランタイム呼び出しの数を削減しました。

ビルトインをC++で書き直すことで、ランタイム呼び出しのオーバーヘッドがなくなり、ICU APIへのアクセスがはるかに高速化しました。

ICUの改善

ICUは、Unicodeおよびグローバリゼーションのサポートを提供するために使用されるC/C++ライブラリセットで、主要なJavaScriptエンジンを含む多くのアプリケーションによって使用されています。IntlをV8のICUベースの実装に切り替える過程で、いくつかICUのバグ発見し、修正しました。

新しい提案を実装する一環として、Intl.RelativeTimeFormatIntl.ListFormatIntl.Localeのような場合、これらの新しいECMAScript提案をサポートするためにICUを拡張し、いくつか新しいAPIを追加しました。

これらの追加は、他のJavaScriptエンジンがこれらの提案を迅速に実装するのを助け、ウェブの進化を推進します!例えば、FirefoxではICU作業を基にした複数の新しいIntl APIの実装が進行中です。

パフォーマンス

この作業の結果として、いくつかの高速なパスを最適化し、さまざまなIntlオブジェクトとNumber.prototypeDate.prototypeString.prototypetoLocaleStringメソッドの初期化をキャッシュすることで、国際化APIの性能を向上させました。

たとえば、新しいIntl.NumberFormatオブジェクトの作成は約24倍高速化されました。

Microbenchmarks 各種Intlオブジェクトの作成性能をテストしたもの

より良いパフォーマンスを得るために、toLocaleStringlocaleCompareのようなメソッドを呼び出す代わりに、Intl.NumberFormatIntl.DateTimeFormat、またはIntl.Collatorオブジェクトを明確に作成して再利用することをお勧めします。

新しいIntl機能

これらすべての作業は、新機能を構築するための素晴らしい基盤を提供しており、ステージ3にある新しい国際化提案をすべて引き続き提供しています。

Intl.RelativeTimeFormat はChrome 71で提供され、Intl.ListFormatはChrome 72で、Intl.LocaleはChrome 74で提供されています。また、Intl.DateTimeFormat用のdateStyletimeStyleオプションおよびIntl.DateTimeFormatのためのBigIntサポートはChrome 76で提供されます。Intl.DateTimeFormat#formatRangeIntl.Segmenter、およびIntl.NumberFormat用の追加オプションが現在V8で開発中で、近日中に提供される予定です!

これらの新しいAPIの多くや、さらにその先にあるものは、開発者が国際化を支援できるように新機能を標準化するための取り組みの成果です。Intl.DisplayNamesは、言語、地域、またはスクリプトの表示名をローカライズできるステージ1の提案です。Intl.DateTimeFormat#formatRangeは、日付範囲を簡潔かつロケール対応でフォーマットする方法を定義するステージ3提案です。統合されたIntl.NumberFormat API提案は、測定単位、通貨表示ポリシー、符号表示ポリシー、科学的記数法、およびコンパクト表記のサポートを追加することでIntl.NumberFormatを改善するステージ3提案です。あなたもそのGitHubリポジトリで貢献することでECMA-402の未来に関与できます。

結論

Intlは、ウェブアプリを国際化する際に必要となるいくつかの操作のための機能豊富なAPIを提供しており、多量のデータやコードを送信することなく、その重労働をブラウザに委ねられます。これらのAPIを適切に使用することで、異なるロケールでUIがより良く機能するようになります。Google V8チームとi18nチームが、TC39とそのサブグループであるECMA-402と協力して取り組んだ成果により、より優れたパフォーマンスでより多くの機能にアクセスできるようになり、将来的にはさらに改善が期待されます。