寫在前面
原文地址:
https://www.bram.us/2019/11/25/faster-javascript-apps-with-json-parse/
原文中包含油管視頻,有梯子並且英文好的可以直接點開鏈接觀看。
針對太長不看的讀者
因為 JSON 語法比 Javascript 的語法更簡單,因此解析 JSON 比解析 Javascript 更高效。當一個 web app 需要加載在首次加載時,解析一個非常複雜的、大型的、符合 JSON 規範的對象字面量配置對象時(比如配置 redux 的 store),我們可以根據這一點來提升首屏加載性能。
為什麼 JSON.parse 更快
使用 AST 表示 JSON.parse(...) 更加簡單
在 AST 中,表示 JSON.parse(...) 更加簡單,只包含一個類型為 CallExpression,一個類型為 StringLiteral 的 token 即可。
而表示等價的對象字面量代碼則複雜的多,複雜程度取決於 JSON 字符串所代表對象的複雜程度,每一個 key 值為一個類型為 StringLiteral 的 token,每一個值為 NumericLiteral 類型的 token,但在 js 中,這個值實際可以為任何類型。
如果對象包含嵌套結構,則會涉及更多的 token 以及值類型,這對於 JS 解釋器來講,將不得不花額外的時間來解析它們以確保代碼能夠正確執行。
解釋 JSON.parse(...) 更加簡單
首先來説 JSON.parse('{ 這段代碼,當解釋器嘗試解釋這段代碼時,只會遇到兩種情況:
- 它是一個合法的
JSON字符串,如果它以{開頭的話 - 它是一個不合法的
JSON字符串
而對於 { 來講,情況就會變得複雜很多,首先來看一段代碼:
const x = 42
const y = ({ x }
對於這段代碼,解釋器讀到這個字節時,無法提前得知後續可能發生的情況。這裏的 y 真得會是對象字面量,還有可能是其他的情況嗎?如果解釋器不執行後續的代碼,它無法得出任何結論。
如果第二行代碼是這樣的:
const y = ({ x })
y 代表一個對象,而這裏的 x 指向第一行代碼中的 x 變量,它是 42。
但如果第二行代碼是這樣的:
const y = ({ x } = { x: 21 })
這裏的 y 就會是 21,第一個 x 是用於結構賦值的,它指向後面對象中的那個值為 21 的 x。
這還沒完,如果代碼是這樣的呢?
const y = ({ x }) => x
這裏 y 則執行一個匿名箭頭函數了,而 x 代表一個結構賦值參數。
這些例子説明,對於 JS 引擎來説,解釋一段代碼,要根據它所處的上下文分析很多事情,而這會花費很多時間,而 JSON.parse 則更加簡單。
benchmark
可以發現在各種不同的 js 引擎中,至少能夠提升 1.5x 的性能。
使用建議
雖然使用 JSON.parse 可以提升性能,但是不建議我們通過手動的方式來應用它,主要有以下兩點原因:
- 使用
JSON.parse比使用 Object 字面量可讀性低 JSON字符串參數無法享受編輯器的高亮效果
建議的做法是,我們可以將這一步驟加入到代碼的編譯打包過程中去,比如使用babel-plugin-object-to-json-parse 插件。(注:這個插件只是實驗版本,穩定之前不建議在生產環境使用)
參考
- https://v8.dev/blog/cost-of-javascript-2019#json
關注公眾號 全棧101,只談技術,不談人生