跳至主要内容

更快且功能更豐富的國際化 API

· 閱讀時間約 5 分鐘
[சத்யா குணசேகரன் (Sathya Gunasekaran)](https://twitter.com/_gsathya)

ECMAScript 國際化 API 規範 (ECMA-402 或 Intl) 提供了關鍵的區域特定功能,例如日期格式化、數字格式化、複數形式選擇和排序。Chrome V8 和 Google 國際化團隊合作為 V8 的 ECMA-402 實現添加功能,同時清理技術債務並改善效能和與其他瀏覽器的互操作性。

底層架構改進

最初,ECMA-402 規範主要在使用 V8 擴展的 JavaScript 中實現,並不在 V8 程式碼庫內部。使用外部擴展 API 意味著 V8 的多個內部使用 API(包括類型檢查、外部 C++ 對象的生命週期管理以及內部私有數據存儲)無法被使用。作為改進啟動效能的一部分,這一實現後來被移動到 V8 程式碼庫內以啟用這些內建的 快照

V8 使用具備特殊 形狀 (隱藏類)JSObject 來描述由 ECMAScript 指定的內建 JavaScript 對象(例如 PromiseMapSet 等)。使用這種方法,V8 能預分配所需的內部槽數量並生成快速訪問,而不是每次只添加一個屬性,導致效能降低和內存使用增加。

Intl 的實現並沒有遵循這種類型的架構,這是由於歷史分裂的結果。相反,所有內建 JavaScript 對象(如 NumberFormatDateTimeFormat)都是通用的 JSObject,必須通過多次屬性添加來過渡其內部槽。

缺乏專門的 JSObject 導致了一個額外問題:類型檢查變得更加複雜。類型資訊儲存在私有符號下,並且通過昂貴的屬性訪問來檢查類型,而不是直接檢查形狀。

現代化程式碼庫

隨著目前逐漸遠離在 V8 中編寫自托管內建程式碼,這次正好是現代化 ECMA402 實現的好時機。

遠離自托管 JavaScript

儘管自托管有助於簡潔和可讀性程式碼,頻繁使用慢速運行時調用來訪問 ICU API 導致了效能問題。因此,大量 ICU 功能被重複實現在 JavaScript 中以減少這些運行時呼叫的次數。

通過用 C++ 重寫內建函數,現在訪問 ICU API 變得更快,因為不再有運行時呼叫的開銷。

改善 ICU

ICU 是一套 C/C++ 庫,用於提供 Unicode 和全球化支持,被眾多應用程序使用,包括所有主要的 JavaScript 引擎。作為將 Intl 切換到 V8 中的 ICU 的一部分,我們找到了 修復了 幾個 ICU 錯誤。

在實現新提案如 Intl.RelativeTimeFormatIntl.ListFormatIntl.Locale 的過程中,我們通過新增幾個 API 擴展了 ICU,以支持這些新的 ECMAScript 提案。

所有這些改進幫助其他 JavaScript 引擎更快實現這些提案,推動了 Web 的進展!例如,Firefox 正在基於我們的 ICU 工作開發多個新的 Intl API。

效能

通過這項工作,我們通過優化多個快速路徑和緩存各種 Intl 對象的初始化以及 Number.prototypeDate.prototypeString.prototype 上的 toLocaleString 方法,改善了國際化 API 的效能。

例如,創建新的 Intl.NumberFormat 對象的速度提高了約 24 倍。

微基準測試 測試創建各種 Intl 對象的效能

請注意,為了更好的效能,建議顯式創建並重複使用 Intl.NumberFormatIntl.DateTimeFormatIntl.Collator 物件,而不是直接調用像 toLocaleStringlocaleCompare 這樣的方法。

新的 Intl 功能

所有這些工作為構建新功能提供了良好的基礎,而且我們正在繼續發布所有處於第三階段的國際化提案。

Intl.RelativeTimeFormat 已在 Chrome 71 中推出,Intl.ListFormat 已在 Chrome 72 中推出,Intl.Locale 已在 Chrome 74 中推出,而 Intl.DateTimeFormatdateStyletimeStyle 選項Intl.DateTimeFormat 的 BigInt 支援 也在 Chrome 76 中推出。Intl.DateTimeFormat#formatRangeIntl.SegmenterIntl.NumberFormat 的附加選項 正在 V8 中開發,我們希望能很快發布它們!

其中許多新 API 和其他尚未推出的功能,都是因為我們致力於標準化新功能以幫助開發者進行國際化。Intl.DisplayNames 是一個第一階段的提案,允許用戶本地化語言、地區或文字的顯示名稱。Intl.DateTimeFormat#formatRange 是一個第三階段的提案,規範了一種以簡潔且符合語言環境的方式格式化日期範圍的方法。統一的 Intl.NumberFormat API 提案 是一個第三階段的提案,它通過新增對測量單位、貨幣與符號顯示政策,以及科學與緊湊符號法的支援來改進 Intl.NumberFormat。您也可以通過在其 GitHub 儲存庫中貢獻來參與 ECMA-402 的未來。

結論

Intl 提供了一個功能豐富的 API,用於國際化您的網頁應用所需的多種操作,減少了數據或程式碼的傳輸負擔,並將繁重的工作交給瀏覽器完成。正確思考這些 API 的使用方式可以使您的使用者界面在不同語言環境下表現得更好。由於 Google V8 和 i18n 團隊與 TC39 及其 ECMA-402 小組的合作,您現在可以使用更多功能且帶來更好的效能,並期待未來進一步的改進。