繁体   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