首页 > 解决方案 > JS引擎处理数据,为什么不符合预期值

问题描述

我正在测试 JS 引擎处理不同级别数据的能力。但是这个结果让我很惊讶。

const step = [10,100,1000,10000,100000,1000000,10000000,100000000,1000000000];
let sum = 0;
step.forEach((item) => {
	let n = item.toString().split('').length -1;
	console.time(`10^${n}`);
	while (item){
		++sum;
		--item;
	}
	console.timeEnd(`10^${n}`);
})

10^1 比 10^3 慢,或 10^5 比 10^6 慢,或两者兼而有之。

测试的runtime包括:chrome71,node 10.13.0,firefox64(还不错)

我不知道这是否是 V8 的行为。

我遵循了CertainPerformance的建议使用performance.now()

// nodeJs
//const { performance } = require('perf_hooks');

const step = [10,100,1000,10000,100000,1000000,10000000,100000000,1000000000];
let sum = 0;
step.forEach((item) => {
	let n = item.toString().split('').length -1;
	let t0 = performance.now();
	while (item){
		++sum;
		--item;
	}
	let t1 = performance.now();
	console.log(`10^${n}:`,t1-t0);
})

它会出现多次。

标签: javascript

解决方案


您应该多次运行代码,因为代码第一次运行时,它永远不会优化,并且在您运行此代码时,JS 引擎会开始优化部分代码/功能。当你再次按下“运行代码片段”时,从技术上讲,它是一个新代码,优化器需要重新开始。

你会发现它在第一次运行后更加一致:

而且我不会过多地阅读 <0.1ms 范围内的波动以及由此产生的第一项之间的顺序差异。

const step = [10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000];
let sum = 0;
const test = (item) => {
  let n = item.toString().split('').length - 1;
  console.time(`10^${n}`);
  while (item) {
    ++sum;
    --item;
  }
  console.timeEnd(`10^${n}`);
};

const runTest = (times) => {
  if (times > 0) {
    sum = 0;
    step.forEach(test);
    console.log("----");
    setTimeout(runTest, 10, times - 1);
  }
}

runTest(10);
.as-console-wrapper {
  top: 0;
  max-height: 100%!important
}

旁注:您会看到,如果您不重置sum = 0,运行几次后,运行时会上升。这是因为sum达到了一个不再可以表示为 anint而是变成 a 的值double。这不仅++sum会稍微贵一点,而且由于迭代次数太多而加起来,而且它还否定了优化器对代码中类型的假设sum,这导致代码的 deopt 和之后的 100-150迭代(未优化)在新假设下对代码的重新优化sumintor double,这也++sum比它只是一个int.


推荐阅读