网站搜索

date - 在 JavaScript 中使用 setTimeout 让函数运行更快


我有一个应用程序,我必须向数组中推送很多值,所以我测试了执行时间:

var st = new Date().getTime();
var a = [];
for (var i = 0; i < 20971520; i++) {
  a.push(i);
}
var ed = new Date().getTime();
console.info((ed - st) / 1000);
console.info(a.length);

我直接在 Firefox 控制台和 Chrome 控制台运行代码,耗时 37 秒。在执行过程中,即使在 Chrome 中鼠标可以移动,但没有互动效果。

然后我更改了代码:

function push() {
  var st = new Date().getTime();
  var a = [];
  for (var i = 0; i < 20971520; i++) {
    a.push(i);
  }
  var ed = new Date().getTime();
  console.info((ed - st) / 1000);
  console.info(a.length);
}

var tr = setTimeout(push, 50);

将代码简化放入一个函数中,并使用 setTimeout 调用它,耗时 0.844 秒。在执行期间,我可以正常在 Chrome 中操作。

这里发生了什么?

我知道 setTimeout 会将控制权交给浏览器来处理 UI 工作,这会使页面保持响应。例如,当我在页面的 mousemove 期间进行一些计算时,我会将计算延迟执行,以防止它阻塞 UI。

但是为什么它会减少相同代码的总执行时间?

答案#1

在执行过程中,我可以正常在 Chrome 中操作。

不对。主 Chrome 窗口会像其他情况一样冻结(只是时间更短)。调试工具是独立的线程,不会变慢。

但是为什么它会减少相同代码的总执行时间?

如果你在开发工具中运行,它确实会这样。如果你在实际环境中执行代码,让虚拟机可以进行属性优化,时间是可比较的(几乎1秒)。例如。

   var st = new Date().getTime();
   var a = [];
   for (var i = 0; i < 20971520; i++) {
       a.push(i);
   }
   var ed = new Date().getTime();
   console.info('normal', (ed - st) / 1000);
   console.info(a.length);

   function push() {
       var st = new Date().getTime();
       var a = [];
       for (var i = 0; i < 20971520; i++) {
           a.push(i);
       }
       var ed = new Date().getTime();
       console.info('timeout', (ed - st) / 1000);
       console.info(a.length);
   }

   var tr = setTimeout(push, 0);

http://jsfiddle.net/gu9Lg52j/ 你会看到 normal 执行得 和 setTimeout 一样快。

另外,如果你将代码包装在一个函数中并在控制台中执行,即使没有 setTimeout,时间也会是可比的,因为虚拟机可以在函数定义和执行之间进行优化:

  function push() {
       var st = new Date().getTime();
       var a = [];
       for (var i = 0; i < 20971520; i++) {
           a.push(i);
       }
       var ed = new Date().getTime();
       console.info('timeout', (ed - st) / 1000);
       console.info(a.length);
   }
   push();

答案#2

这两种代码变体的运行速度应该几乎相同(后一个示例可能更快,但不会快十倍)。

在 Chrome 开发者工具中,情况就不同了。表达式是在一个 with 块内进行求值的。这意味着像 a 和 i 这样的变量会先在另一个对象(__commandLineAPI)中搜索。这增加了额外的开销,从而导致执行时间长了 10 倍。