Javascript' setInterval()似乎不关注它调用的代码是否会引发异常。例如,这不会终止程序,而是一遍又一遍地调用函数:
setInterval(function() { throw "error" }, 1000);
这种行为的原因是什么?是否记录在任何地方?
答案 0 :(得分:4)
throw
的MDN文档说,对于抛出的对象:
如果调用函数之间不存在catch块,程序将终止。
这并非严格准确。 ECMAScript spec section 10.4
抛出的异常也可能会退出一个或多个执行上下文。
这更准确。
什么是执行上下文?那么,有一个原始程序。进行函数调用时,将在该函数运行时创建嵌套上下文。拨打eval
即可拨打电话。 10.4涵盖了这一点。
通常,当抛出异常时,它将向上传递所有嵌套的执行上下文,直到它被捕获,或者它到达外部执行上下文。如果未在执行上下文中捕获,则将终止该上下文。因此,如果您的原始程序是最外层的执行上下文,它将终止于未捕获的异常?
调用处理程序函数时,由于setTimeout
间隔到期,它是最外层的执行上下文。因此,未捕获的异常终止它,但它不嵌套在您的原始程序中。所以没有其他东西被终止。
处理计时器的线程到期是JS引擎的一部分,所以你也不会终止它。因此,每个间隔一次,在调用处理函数时会创建一个新的执行上下文,因此它会重复。
答案 1 :(得分:1)
如果您不希望一遍又一遍地调用该函数,请捕获异常并清除计时器。此示例从5开始向下计数,打印到控制台,并在值小于零时抛出异常:
var counter = 5;
var timer;
var decrement = function() {
try {
if ( counter < 0 ) {
clearInterval(timer);
throw new Error("Invalid count");
}
console.log(counter);
counter -= 1;
}
catch ( error ) {
console.error(error);
}
}
timer = setInterval(decrement, 1000);
由您决定是否应该再次调用该函数。异常停止执行该功能,但没有&#34;程序&#34;终止。网络浏览器是&#34;程序&#34;。如果它运行抛出异常的函数,它仍然继续为其他事件提供服务。这是预期的行为。
为什么它不会在异常时取消定时器?尝试加载可能失败的资源并在成功时清除计时器时,您可能需要这样做。
答案 2 :(得分:0)
当你致电setInterval
时,运行时并不知道回调是否会抛出。
var shouldThrow = false;
setInterval(function () {
if (shouldThrow) throw 'error';
console.log('program has not stopped');
}, 5000);
// nothing is wrong at this point.
// thus, the program continues
shouldThrow = confirm('Throw error?');
你会发现如果回调抛出, 终止&#34;程序,&#34;这就是回调本身。在此示例中,如果单击“确定”按钮,则回调将不会继续进行console.log
调用。它会继续反复调用回调。如果您稍后再次更改shouldThrow
,则会在控制台中看到更多消息。