处理异步异常

任何程序都会出错,因此,错误处理在编程中是很重要的一环。尽管,一般错误主要逻辑是存在于服务器端的(因为服务端的应用程序一般都是一直运行着的,错误处理对于应用程序稳定性来说十分重要);但是当浏览器中 JavaScript 脚本发生错误时,浏览器的报告错误方式一般不大讨人喜,这样可能会导致用户的流失之类的。

再者,了解异常的生成和处理对于一个程序的运行也是一种知识的积累。

出现异常会发生什么?

我们知道JavaScript是一门解释性语言,并没有编译时( complie time ),是彻头彻尾的运行时( Runtime ),因此程序的错误异常只会在运行时发生,这意味着程序出现这种错误后,后续的代码将不能够正常执行。

console.log('script start');

function func() {
    console.log('some calc');
    throw new Error('something wrong');
}

func();

console.log('scripit end');

// script start
// some calc
// Uncaught Error: something wrong

因此,对于用户来说,这意味着当前页面可能是无法使用的状态,这样会导致用户体验的下降。

生成异常 throw

通常来说,很多程序语言生成错误都是使用 抛出 来生成一个内置错误对象或自定义错误对象;当然语法和 Java 如此相像的 JavaScript 也不例外,使用 throw 关键字抛出自定义错误对象。

ECMA-262定义了以下8种错误类型:

  • Error

  • InternalError ( passed, only in IE !!! )

  • EvalError

  • RangeError

  • ReferenceError

  • SyntaxError

  • TypeError

  • URIError

EvalError.prototype instanceof Error && EvalError.prototype instanceof Error && RangeError.prototype instanceof Error && ReferenceError.prototype instanceof Error && SyntaxError.prototype instanceof Error && TypeError.prototype instanceof Error && URIError.prototype instanceof Error
// true

其中 Error 是后7种的基类,其他错误累心继承自该类型;而且浏览器中很少会抛出 Error 类型的错误,类型主要用于开 发者抛出自定义错误。而后7种错误类型基本来自于浏览器内置抛出。

抛出一些错误!

window.onerror = (message, url, line) => {
    console.log('error event');
    console.log('message: ', message);
    console.log('url: ', url);
    console.log('line: ', line);
};

console.log('script start');

function globalFn() {
    console.log('globalFn exec');
    function localFn() {
        console.log('localFn exec');
        throw new Error('something wrong inside!');
        console.log("won't console!");
    }	
    localFn();
    console.log("won't console!");
}

globalFn();

console.log('script end');

// script start
// globalFn exec
// localFn exec
// error event
// message:  Uncaught 
// Error: something wrong inside!
// url:  http://localhost:63342/vsProj/%E5%85%AB%E8%82%A1%E6%96%87/html/19-exception.html?_ijt=rhmk5di4q8fnp6g8nbm7ttqcbm&_ij_reload=RELOAD_ON_SAVE
// line: 21
// Uncaught Error: something wrong inside!

由上,异常若不处理不仅影响当前上下文;若当前上下文不对错误进行处理,会继续抛给更上一层的上下文直到浏览器上下文,浏览器会将在出现错误的代码处停止运行,在 console 中打印相应的message。同时,浏览器(window对象)一直在监听一个 error 事件,当错误(未经过处理)出现时触发该事件。

处理异常 try/catch

JavaScript 处理异常也和 Java 一样,使用 trycatch 语句。

console.log('script start');

function globalFn() {
    console.log('globalFn exec');
    function localFn() {
        console.log('localFn exec');
        throw new Error('something wrong inside!');
        // 因为在该上下文并没有直接处理错误,抛给了上一级上下文 globalFn,
        // 导致后续代码不会打印
        console.log("do not catch, won't console!");
    }	
    try{
        localFn();
    }
    console.log("after caught in globalFn ctx, console!");
}

globalFn();

console.log('script end');

// script start
// globalFn exec
// localFn exec
// after caught in globalFn ctx, console!
// script end

很重要的一点是 try...catch 只能处理运行中的错误(源代码必须是可以执行的),因为 JavaScript 引擎在解析期( parse-time )要确保源代码是能够执行的,该时间段出现的错误被称为解析时间错误,这种错误会使得整个 script 都不可以执行,必须移除这些错误。

// 整个源代码都不会执行
try {
    {{{  // 不匹配括号
}catch(e) {
    console.log("won't console!");
}finally {
    console.log("won't console!");
}

try {
    const 
}catch(e) {
    console.log("won't console!");
}finally {
    console.log("won't console!");
}

// output:
// Uncaught SyntaxError: Unexpected token '}' (at

finallyreturn 优先级高:

function func() {
    try {
        return 'try';
    }catch{
        
    }finally{
        return 'higher than try';
    }
}

console.log(func()); // higher than try; 

Reference

  • test cloudflare cache. 24hours