javascript - 为什么负数组索引比正数组索引慢得多?
问题描述
这是一个简单的 JavaScript 性能测试:
const iterations = new Array(10 ** 7);
var x = 0;
var i = iterations.length + 1;
console.time('negative');
while (--i) {
x += iterations[-i];
}
console.timeEnd('negative');
var y = 0;
var j = iterations.length;
console.time('positive');
while (j--) {
y += iterations[j];
}
console.timeEnd('positive');
第一个循环从 10,000,000 计数到 1,并在每次迭代中使用负索引访问长度为 1000 万的数组。所以它从头到尾遍历数组。
第二个循环从 9,999,999 计数到 0,并在每次迭代中使用正索引访问同一个数组。所以它反向通过数组。
在我的电脑上,第一个循环需要超过 6 秒才能完成,但第二个循环只需要约 400 毫秒。
为什么第二个循环比第一个快?
解决方案
因为iterations[-1]
将评估为undefined
(这很慢,因为它必须沿着整个原型链上升并且不能走一条快速的路径)而且用它做数学NaN
总是很慢,因为它是不常见的情况。
同样用数字初始化iterations
将使整个测试更有用。
专业提示:如果您尝试比较两个代码的性能,它们最终都应该导致相同的操作......
关于性能测试的一些通用词:
这些天,性能是编译器的工作,编译器优化的代码总是比你试图通过一些“技巧”优化的代码快。因此,您应该编写可能由编译器优化的代码,并且在任何情况下,都是其他人编写的代码(如果您这样做,您的同事也会喜欢您)。从引擎的角度来看,优化这一点是最有益的。因此我会写:
let acc = 0;
for(const value of array) acc += value;
// or
const acc = array.reduce((a, b) => a + b, 0);
但是最后它只是一个循环,如果循环执行不好,你不会浪费太多时间,但是如果整个算法执行不好(时间复杂度为 O(n²) 或更多),你会浪费很多时间。专注于重要的事情,而不是循环。
推荐阅读
- mysql - 将 MySQL 查询转换为 SQL Server
- bash - 打开终端时“没有这样的文件或目录”
- android - 是否可以在 Android 上的 React-native 中以编程方式隐藏键盘上方的工具栏?
- javascript - 使用 ReactJS 向 Rails 后端提交表单
- python - 为什么我的包占用这么多内存
- azure - 我们可以自动缩放连接到应用程序网关的 Azure 容器实例吗
- google-bigquery - Spotfire - Biquery - Simba JDBC
- java - 发送消息后,套接字神秘地从哈希图中删除
- vb.net - 单击 ListViewGroup 是否有任何事件暴露?
- nestjs - Nestjs在forRootAsync中包装外部模块并注入实例