JavaScript(七)错误处理

错误传播

如果代码发生了错误,又没有被try ... catch捕获,那么,程序执行流程会跳转到哪呢?

function getLength(s) {
    return s.length;
}

function printLength() {
    console.log(getLength('abc')); // 3
    console.log(getLength(null)); // Error!
}

printLength();

如果在一个函数内部发生了错误,它自身没有捕获,错误就会被抛到外层调用函数,如果外层函数也没有捕获,该错误会一直沿着函数调用链向上抛出,直到被JavaScript引擎捕获,代码终止执行。

所以,我们不必在每一个函数内部捕获错误,只需要在合适的地方来个统一捕获,一网打尽:

'use strict';
function main(s) {
    console.log('BEGIN main()');
    try {
        foo(s);
    } catch (e) {
        console.log('出错了:' + e);
    }
    console.log('END main()');
}

function foo(s) {
    console.log('BEGIN foo()');
    bar(s);
    console.log('END foo()');
}

function bar(s) {
    console.log('BEGIN bar()');
    console.log('length = ' + s.length);
    console.log('END bar()');
}

main(null);


/*运行结果:
BEGIN main()
BEGIN foo()
BEGIN bar()
出错了:TypeError: Cannot read property 'length' of null
END main()
*/

bar()函数传入参数null时,代码会报错,错误会向上抛给调用方foo()函数,foo()函数没有try ... catch语句,所以错误继续向上抛给调用方main()函数,main()函数有try ... catch语句,所以错误最终在main()函数被处理了。

至于在哪些地方捕获错误比较合适,需要视情况而定。

 

 

异步错误处理

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

例如,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) {
    console.log('error');
}

//运行结果
//done

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

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

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

例如,针对以下的表单:

<form>
    <input id="x"> + <input id="y">
    <button id="calc" type="button">计算</button>
</form>

 

对当前的内容进行计算方式如下:

$btn.click(function () {

try {

        var

            x = parseFloat($('#x').val()),

            y = parseFloat($('#y').val()),

            r;

        if (isNaN(x) || isNaN(y)) {

            throw new Error('输入有误');

        }

        r = x + y;

        alert('计算结果:' + r);

}

 

posted @ 2021-08-23 20:11  陈晓猛  阅读(48)  评论(0编辑  收藏  举报