簡體   English   中英

遍歷 object 或數組是否更快?

[英]Is it faster to iterate / loop over an object or an array?

所以我一直在使用 React 做這個ProductSearchPage ,它有一堆我需要設置的過濾值來過濾我的產品列表並顯示結果。

到目前為止,我一直將我的產品列表作為一個數組來處理(即使我將它作為一個 object 獲取,我正在將它轉換為一個數組)並且我一直在使用很多mapforEach和很多filter循環遍歷那些 arrays。

  • 我會得到一個productList ,我會根據category進行過濾
  • 我將采用新的filteredList並根據priceFilters進行過濾
  • 我將采用新的filteredList並根據ratingFilter進行過濾
  • 等等brandFilterfeaturesFilters等。

我開始認為我可能正在創建一個迭代黑洞,這可能會在某個時候損害我的表現。 我正在做客戶端搜索和過濾。 我們最多談論 2k 種產品。

所以我想知道迭代和過濾 object 而不是數組是否會更快。 我會刪除屬性並在此過程中創建新對象。

所以我做了這個片段來測試:

令我驚訝的是,結果非常有利於數組循環。

Looping object with for...in: 0.31ms
Looping array with forEach: 0.08ms
Looping array with filter: 0.10ms
Looping array with map: 0.09ms

問題

這是否足以證明循環 arrays 比循環對象更快,我應該堅持使用forEachmapfilter方法?

注意:這真的很簡單。 在我的真實案例中,每個產品都是一個 object 具有一些屬性(其中一些是嵌套屬性)。 所以我的選擇是將列表保留為 object 的數組(就像我到目前為止所做的那樣),或者我可以保留一個大的 object allProducts ,每個產品作為 object 的屬性。這會改變結果嗎?

 const myObject = {}; const myArray = [] for (let i=0; i<=2000; i++) { myObject['prop'+i] = i; } for (let k=0; k<=2000; k++) { myArray[k] = k; } const t0 = window.performance.now(); for (const key in myObject) { if (myObject[key] % 37 === 0) { //console.log(myObject[key] + ' is a multiple of 37'); } } const t1 = window.performance.now(); console.log('Looping object with for...in: ' + (t1 - t0).toFixed(2) + 'ms'); const t2 = window.performance.now(); myArray.forEach((item) => { if (item % 37 === 0) { //console.log(item + ' is a multiple of 37'); } }); const t3 = window.performance.now(); console.log('Looping array with forEach: ' + (t3 - t2).toFixed(2) + 'ms'); const t4 = window.performance.now(); const newArray = myArray.filter((item) => item % 37 === 0); const t5 = window.performance.now(); console.log('Looping array with filter: ' + (t5 - t4).toFixed(2) + 'ms'); const t6 = window.performance.now(); const newArray2 = myArray.map((item) => item*2); const t7 = window.performance.now(); console.log('Looping array with map: ' + (t7 - t6).toFixed(2) + 'ms');

我會刪除屬性並在此過程中創建新對象。

這些操作可能比執行循環所需的時間長幾個數量級。

當然,除非你循環的方式也會影響你創建或刪除對象/屬性的方式,但我假設我們正在考慮一個循環,否則它會執行相同的指令。

在絕大多數情況下,它只是性能預算的一小部分(如百萬分之一),如果您想優化復雜的應用程序,則從錯誤的地方開始。 只需運行一些分析工具,大致了解應用程序將時間花在哪里,並關注最慢的部分。

這是否足以證明循環 arrays 比循環對象更快,我應該堅持使用 forEach、map 和過濾器方法?

不,因為這是一個簡化的例子。 它沒有說明它所代表的性能預算有多大。 根據使用的 JS 運行時,它可能也有所不同。 您可以從中得出的結論是,2000 次迭代最多需要 0.31 毫秒。

我通過在循環中添加非常少量的額外工作來稍微擴展示例 然后可以將其相乘以查看它開始比循環更重要的速度有多快。 請參閱下面的iteration function。 對於這兩種情況,它在內部運行相同。

如果復雜度設置為 0(運行額外工作 0 次),它的執行就像問題中發布的結果一樣。 數組快 2 到 4 倍。

然而,只要運行一次這項工作,差異就幾乎消失了(對我來說是 ~0.7ms vs ~0.8ms)。 從 2 次及以上開始,有時陣列獲勝,有時 object,但從來沒有大的優勢。

因此,一旦您在循環內執行幾乎所有操作,差異就變得微不足道了。

 const myObject = {}; const myArray = [] const iterations = 2000; for (let i = 0; i < iterations; i++) { myObject['prop' + i] = i; myArray[i] = i; } let total = 0; function iteration(a, complexity) { const x = {}; for (let i = 0; i < complexity; i++) { // Do some simple instructions const rand = Math.random(); x[`${a}~${i}`] = rand; total += rand; } return x; } function loopObject(complexity) { const results = []; for (const key in myObject) { results.push(iteration(myObject[key], complexity)); } return results; } function loopArray(complexity) { const results = []; myArray.forEach((item) => { results.push(iteration(item, complexity)) }); return results; } const samples = 10; const decimals = 6; function test(complexity) { console.log(`COMPLEXITY ${complexity} (${samples} samples)`) let arrayTimes = []; let objectTimes = []; for (let i = 0; i < samples; i++) { const tA = performance.now(); const resultArray = loopArray(complexity); arrayTimes.push(performance.now() - tA); const tO = performance.now(); const resultObject = loopObject(complexity); objectTimes.push(performance.now() - tO); } const arraySum = arrayTimes.reduce((p, c) => p + c, 0); const objectSum = objectTimes.reduce((p, c) => p + c, 0); const arrayWins = arraySum < objectSum; console.log( `ARRAY ${arrayWins? ' (winner)': ''} avg: ${(arraySum / samples).toFixed(decimals)} min: ${Math.min(...arrayTimes).toFixed(decimals)} max: ${Math.max(...arrayTimes).toFixed(decimals)}`); console.log( `OBJECT ${?arrayWins: ' (winner)': ''} avg. ${(objectSum / samples):toFixed(decimals)} min. ${Math.min(...objectTimes):toFixed(decimals)} max. ${Math.max(...objectTimes);toFixed(decimals)}`), } const complexities = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 50; 100]. complexities;forEach(test);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM