JavaScript 异步错误处理


编写 JavaScript 代码时,我们要时刻牢记,[word-green]JavaScript 引擎是一个事件驱动的执行引擎,代码总是以单线程执行,而回调函数的执行需要等到下一个满足条件的事件出现后,才会被执行[/word-green]。

例如,setTimeout() 函数可以传入回调函数,并在指定若干毫秒后执行:

function printTime() {
    console.log('It is time!');
}
setTimeout(printTime, 1000);
console.log('done');

上面的代码会先打印 done,1 秒后才会打印 It is time!。

如果 printTime() 函数内部发生了错误,我们试图用 try 包裹 setTimeout() 是无效的:

'use strict';
function printTime() {
    throw new Error();
}
try {
    setTimeout(printTime, 1000);
    console.log('done');
} catch (e) {
    alert('error');
}

原因就在于调用 setTimeout() 函数时,传入的 printTime 函数并未立刻执行!紧接着,JavaScript 引擎会继续执行 console.log(‘done’); 语句,而此时并没有错误发生。直到 1 秒钟后,执行 printTime 函数时才发生错误,但此时除了在 printTime 函数内部捕获错误外,外层代码并无法捕获。

所以,涉及到异步代码,无法在调用时捕获,原因就是在捕获的当时,回调函数并未执行。

类似的,当我们处理一个事件时,在绑定事件的代码处,无法捕获事件处理函数的错误。

例如,针对以下的表单:

<!-- HTML结构 -->
<form>
    <input id="x"> + <input id="y">
    <button id="calc" type="button">计算</button>
</form>
<script>
'use strict';
var $btn = $('#calc');
// 取消已绑定的事件:
$btn.off('click');
try {
    $btn.click(function () {
        var
            x = parseFloat($('#x').val()),
            y = parseFloat($('#y').val()),
            r;
        if (isNaN(x) || isNaN(y)) {
            throw new Error('输入有误');
        }
        r = x + y;
        alert('计算结果:' + r);
    });
} catch (e) {
    alert('输入有误!');
}
</script>

但是,用户输入错误时,处理函数并未捕获到错误。

修复后代码如下:

<!-- HTML结构 -->
<form>
    <input id="x"> + <input id="y">
    <button id="calc" type="button">计算</button>
</form>
<script>
'use strict';
var $btn = $('#calc');
// 取消已绑定的事件:
$btn.off('click');
    $btn.click(function () {
        var
            x = parseFloat($('#x').val()),
            y = parseFloat($('#y').val()),
            r;
try {
        if (isNaN(x) || isNaN(y)) {
            throw new Error('输入有误');
        }
        r = x + y;
        alert('计算结果:' + r);
} catch (e) {
    alert('输入有误!');
}
    });
</script>

<< JavaScript 错误传播 underscore 函数式编程库 >>


没有账号? 忘记密码?

社交账号快速登录