大循环挂起javascript引擎

时间:2014-10-11 06:51:08

标签: javascript node.js google-chrome firefox for-loop

最近,当我解决算法问题时,我发现了一个像这样的简单的大循环

var x = 1000000000000;
for (var i = 0; i <= x; i++) {}

可以挂起javascript引擎(在node.js,Chrome和Firefox javascript控制台上测试)。

实际上它正在运行,但速度很慢。我尝试了几个x的值,当x = 1000000时有明显的延迟。

这种表现是否与翻译语言一致?

3 个答案:

答案 0 :(得分:2)

你可以使用某种形式的loop unrolling,将循环分解成块,例如使用Duffs device,或使用描述here的机制。

行为不仅限于解释型语言。循环将持续很长很长时间。请尝试使用c#中的for (long n = 1000000000000; n >= 0; n-=1) {}

最后,在(现代)浏览器中使用web workers可能是可行的。我在an example创建了另一个SO问题。

答案 1 :(得分:2)

任何语言都会很慢。在这种情况下,它特别引人注目,因为它会阻止您的用户界面。 JavaScript引擎执行单线程事件循环。您始终可以use web workers在后台执行缓慢的处理任务。

答案 2 :(得分:0)

我在MacBook Pro笔记本电脑上测试过,在现实情况下应该没问题:

  • 1,000,000次循环迭代
  • 每次迭代都调用一个(简单的)函数
  • 在前几轮中需要2-3毫秒(冷编译器)
  • 之后大约需要0.5毫秒(编译器会优化热代码)

如果您需要遍历超大型值,我将其拆分为较小的垃圾,并使用setTimeoutrequestAnimationFrame将工作负载分散到不同的帧上,而不会导致任何帧丢失(框架需要约16ms的时间来完成所有工作)。

console.clear();

// options
const start = true;
const useFastTick = false; // 3ms per tick vs e.g 1s
const interval = 1; // 1: once/sec, 2: twice/sec, etc
const iterations = 1000000;

function emptyFn() {}

function argsFn(obj) {}

function emptyFns() {
  for (let i = 0; i < iterations; i++) {
    if (i !== undefined && i !== null) emptyFn();
  }
}

function argsFns() {
  for (let i = 0; i < iterations; i++) {
    argsFn({a: 'hey', b: i, c: false});
  }
}


function tick() {
  const all0 = performance.now();

  const empty0 = performance.now();
  emptyFns();
  const empty1 = performance.now();

  const args0 = performance.now();
  argsFns();
  const args1 = performance.now();

  const all1 = performance.now();

  const all = (all1 - all0).toFixed(3);
  const empty = (empty1 - empty0).toFixed(3);
  const args = (args1 - args0).toFixed(3);
  log(all, empty, args);

  if (useFastTick) {
    setTimeout(tick, 3);
  } else {
    setTimeout(() => requestAnimationFrame(tick), 1000 * interval);
  }
}

if (start) requestAnimationFrame(tick);



// log results to console
function log(all, empty, args) {
  console.group(`${all}ms`);
  console.log(`Empty: ${empty}ms`);
  console.log(`Arrgs: ${args}ms`);
  console.groupEnd();
}