這是在與我的朋友討論遞歸時提出的。為什麼不建造
Javascript JSON.stringify 方法作為遞歸程式設計練習?看起來很棒
主意。
我很快就起草了第一個版本。而且表現很糟糕!
所需時間約為標準的 4 倍 JSON.stringify。
function json_stringify(obj) { if (typeof obj == "number" || typeof obj == "boolean") { return String(obj); } if (typeof obj == "string") { return `"${obj}"`; } if (Array.isArray(obj)) { return "[" + obj.map(json_stringify).join(",") + "]"; } if (typeof obj === "object") { const properties_str = Object.entries(obj) .map(([key, val]) => { return `"${key}":${json_stringify(val)}`; }) .join(","); return "{" + properties_str + "}"; } }
透過執行以下指令,我們可以看到我們的 json_stringify 的工作方式為
預計。
const { assert } = require("console"); const test_obj = { name: "John Doe", age: 23, hobbies: ["football", "comet study"] }; assert(json_stringify(test_obj) === JSON.stringify(test_obj))
測試更多場景,並進行多次運行,以大致了解我們的
腳本運行,我們製作了一個簡單的測試腳本!
function validity_test(fn1, fn2, test_values) { for (const test_value of test_values) { assert(fn1(test_value) == fn2(test_value)); } } function time(fn, num_runs = 1, ...args) { const start_time = Date.now() for (let i = 0; i < num_runs; i++) { fn(...args); } const end_time = Date.now() return end_time - start_time } function performance_test(counts) { console.log("Starting performance test with", test_obj); for (const count of counts) { console.log("Testing", count, "times"); const duration_std_json = time(JSON.stringify.bind(JSON), count, test_obj); console.log("\tStd lib JSON.stringify() took", duration_std_json, "ms"); const duration_custom_json = time(json_stringify, count, test_obj); console.log("\tCustom json_stringify() took", duration_custom_json, "ms"); } } const test_obj = {} // a deeply nested JS object, ommitted here for brevity const test_values = [ 12, "string test", [12, 34, 1], [12, true, 1, false], test_obj ]; validity_test(JSON.stringify, json_stringify, test_values); performance_test([1000, 10_000, 100_000, 1000_000]);
運行這個我們得到如下的計時。
Testing 1000 times Std lib JSON.stringify() took 5 ms Custom json_stringify() took 20 ms Testing 10000 times Std lib JSON.stringify() took 40 ms Custom json_stringify() took 129 ms Testing 100000 times Std lib JSON.stringify() took 388 ms Custom json_stringify() took 1241 ms Testing 1000000 times Std lib JSON.stringify() took 3823 ms Custom json_stringify() took 12275 ms
它可能在不同的系統上運作不同,但所花費的時間比例
透過 std JSON.strngify 到我們自訂的 json_stringify 應該是關於
1:3 - 1:4
在一個有趣的案例中,情況也可能有所不同。繼續閱讀以了解更多關於
那個!
首先可以解決的是地圖功能的使用。它創造了
舊數組中的新數組。在我們的物件範例中,它會建立一個
陣列
包含物件條目的陣列中的 JSON 字串化物件屬性。
陣列元素的字串化也會發生類似的情況。
我們必須循環遍歷數組中的元素或物件的條目!但是
我們可以跳過建立另一個陣列來連接 JSON 字串化部分。
這是更新版本(為簡潔起見,僅顯示更改的部分)
function json_stringify(val) { if (typeof val === "number" || typeof val === "boolean") { return String(val); } if (typeof val === "string") { return `"${val}"`; } if (Array.isArray(val)) { let elements_str = "[" let sep = "" for (const element of val) { elements_str += sep + json_stringify(element) sep = "," } elements_str += "]" return elements_str } if (typeof val === "object") { let properties_str = "{" let sep = "" for (const key in val) { properties_str += sep + `"${key}":${json_stringify(val[key])}` sep = "," } properties_str += "}" return properties_str; } }
這是現在測試腳本的輸出
Testing 1000 times Std lib JSON.stringify() took 5 ms Custom json_stringify() took 6 ms Testing 10000 times Std lib JSON.stringify() took 40 ms Custom json_stringify() took 43 ms Testing 100000 times Std lib JSON.stringify() took 393 ms Custom json_stringify() took 405 ms Testing 1000000 times Std lib JSON.stringify() took 3888 ms Custom json_stringify() took 3966 ms
現在看起來好多了。我們的自訂 json_stringify 只花費 3 毫秒
比 JSON.stringify 能夠對深層巢狀物件進行字串化 10,000 次。
雖然這並不完美,但這是可以接受的延遲。
當前的延遲可能是由於所有字串創建和連接
這正在發生。每次我們執行 elements_str += sep + json_stringify(element)
我們正在連接 3 個字串。
連接字串的成本很高,因為它需要
透過我們自己使用緩衝區並直接將資料寫入那裡可能會給我們
性能改進。因為我們可以建立一個大緩衝區(例如 80 個字元)
然後創建新的緩衝區以容納 80 個字符,當它用完時。
我們不會完全避免資料的重新分配/複製,但我們會
減少這些操作。
另一個可能的延遲是遞歸過程本身!具體來說
函數呼叫會佔用時間。考慮我們的函數呼叫 json_stringify(val)
它只有一個參數。
步驟是
所有這些操作都是為了確保函數呼叫發生,這會增加 CPU
費用。
如果我們建立一個非遞歸的 json_stringify 演算法來完成所有這些操作
上面列出的函數呼叫(乘以此類呼叫的次數)將為
減少到沒有。
這可以是未來的嘗試。
這裡需要注意的最後一件事。考慮測試腳本的以下輸出
Testing 1000 times Std lib JSON.stringify() took 8 ms Custom json_stringify() took 8 ms Testing 10000 times Std lib JSON.stringify() took 64 ms Custom json_stringify() took 51 ms Testing 100000 times Std lib JSON.stringify() took 636 ms Custom json_stringify() took 467 ms Testing 1000000 times Std lib JSON.stringify() took 6282 ms Custom json_stringify() took 4526 ms
我們的自訂 json_stringify 是否比 NodeJs 標準表現更好
JSON.stringify???
嗯,是的!但這是舊版的 NodeJs (v18.20.3)。事實證明,對於
這個版本(也可能更低)我們客製化的 json_stringify 可以工作
比標準庫更快!
本文的所有測試(除了最後一個)均已使用
完成
節點 v22.6.0
JSON.stringify 的效能從 v18 提升到了 v22。這太棒了
還要注意的是,我們的腳本在 NodeJs v22 中表現得更好。
所以,這意味著 NodeJs 也提高了運行時的整體效能。
底層V8引擎本身可能發生了更新。
嗯,這對我來說是一次愉快的經驗。我希望這是為了
你也是。在所有這些享受中,我們學到了一兩件事!
繼續構建,繼續測試!
以上是與 JSON.stringify 競爭 - 透過建立自訂的 JSON.stringify的詳細內容。更多資訊請關注PHP中文網其他相關文章!