为什么以下JS代码不会在浏览器中终止?

问题描述 投票:4回答:2
function foobar() {
  console.log('baz');    
  setTimeout(() => foobar(), 1000);
}

foobar();
throw new Error('terminate');

我假设foobar函数对在1s之后执行的回调进行排队,退出堆栈,然后main函数抛出错误,事情应该终止。但是,如果在浏览器中运行则不会。

javascript browser event-loop
2个回答
2
投票

这个例子更好地说明了这一点:

let attempts = 10;
function foobar() {
  if (!attempts--) return; // make it stop!
  console.log('baz');
  setTimeout(foobar, 1000);  
  throw new Error('terminate');
}
foobar();

请参阅抛出错误会终止当前任务的执行,但不会终止浏览器event loop。并且事件循环已经在其队列中有另一个任务 - 在抛出Error之前由setTimeout调度。冲洗并重复。


然而,Node.js中的情况有所不同:第一个未捕获的异常基本上停止了整个过程的执行。这就是Node的哲学 - fail early - 尽管questioned,但它的存在方式却是如此。

不过,经过微小的修改,你会看到类似的图片。只需将这些行添加到脚本中:

process.on('uncaughtException', function (err) {
  console.error('CAUGHT', err);
});

......你会看到非常相似的模式。


1
投票

成为JavaScript解释器。

让我们看一下任务列表,JavaScript解释器必须做的事情:


任务列表

[执行主要代码]


现在解释器逐行执行任务。

执行foobar(); JavaScript解释器将在其任务列表中推送一个新任务,该任务列表包含要执行的setTimeout()函数。


任务列表

[执行主代码(进行中)] [执行setTimeout函数]


然后当它到达throw时,它会抛出一个错误并终止实际的任务执行。

它需要执行下一个任务并执行它:


任务列表

[执行setTimeout函数(进行中)]


执行setTimeout函数,它再次推送一个新任务(它刚刚执行)。

又一次又一次又一次......


    function foobar() {
      console.log('baz');    
      setTimeout(() => foobar(), 1000);
    }
    
    foobar();
    throw new Error('terminate');
© www.soinside.com 2019 - 2024. All rights reserved.