目录

🔦 JavaScript 的错误处理

# try...catch 结构

try {

  // 代码...

} catch (err) {

  // 错误捕获

}
1
2
3
4
5
6
7
8
9

其中 err 将包含一个 error 对象,该对象包含了所发生事件的详细信息。

🌰 例子:

try {
  console.log('Start of try runs');  // (1) <--
  lalala; // Error,变量未定义!
  console.log('End of try (never reached)');  // (2)
} catch (err) {
  console.log(err); // (3) <--
}
1
2
3
4
5
6
7

提示

try...catch 仅对运行时的 error 有效

要使得 try...catch 能工作,代码必须是可执行的。换句话说,它必须是有效的 JavaScript 代码。如果代码包含语法错误,那么 try..catch 将无法正常工作(编译错误)。

try...catch 只能处理有效代码中出现的错误(运行错误),或者为 异常。

提示

在使用如 setTimeout 定时器 计划的代码时,应该:

setTimeout(function() {
  try {
    noSuchVariable; // try...catch 处理 error 了!
  } catch {
    alert( "error is caught here!" );
  }
}, 1000);
1
2
3
4
5
6
7

如果在 setTimeout 外部使用则捕获不了错误,因为引擎已经离开了 try ... catch 结构。

# Error 对象

发生错误时,JavaScript 生成包含错误有关其详细信息的对象,作为参数传送给 catch

内建的 Error 对象中包含:

  • name :``Error` 名称。
  • message :关于错误的详细文字描述。
  • stack :当前的调用栈:用于调试目的的一个字符串,其中包含有关导致 error 的嵌套调用序列的信息。

🌰 例子:

try {
  lalala; // error, variable is not defined!
} catch (err) {
  alert(err.name); // ReferenceError
  alert(err.message); // lalala is not defined
  alert(err.stack); // ReferenceError: lalala is not defined at (...call stack)

  // 整体错误对象输出
  alert(err); // ReferenceError: lalala is not defined
}
1
2
3
4
5
6
7
8
9
10

提示

新增的 JavaScript 特性中,可以不使用 Error 对象:

try {
  // ...
} catch {
  // ...
}
1
2
3
4
5

# 抛出 Error 对象

使用 throw 操作符会生成一个 error 对象。

🌰 例子:

let json = '{ "age": 30 }'; // 不完整的数据

try {

  let user = JSON.parse(json); 

  if (!user.name) {
    throw new SyntaxError("Incomplete data: no name");
  }

  alert( user.name );

} catch(err) {
  alert( "JSON Error: " + err.message ); // JSON Error: Incomplete data: no name
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

再次抛出错误 Error 对象catch 应该只处理它知道的 error,并在此抛出所有其他 error。

🌰 例子:

let json = '{ "age": 30 }'; // 不完整的数据
try {

  let user = JSON.parse(json);

  if (!user.name) {
    throw new SyntaxError("Incomplete data: no name");
  }

  blabla(); // 预料之外的 error

  alert( user.name );

} catch (err) {

  if (err instanceof SyntaxError) {
    alert( "JSON Error: " + err.message );
  } else {
    throw err; // 再次抛出 (*)
  }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

catch 中只处理了 SyntaxError ,对于其他错误,再次抛出,交由外部的 try…catch 结构处理,如果没有被处理则 脚本就会被杀死。

# finally

finally 子句通常用在:当开始做某事的时候,希望无论出现什么情况都要完成完成某个任务。

无论是 有无出现错误,都会执行 finally 中的工作。

🌰 例子:

try {
  confirm( 'try' );
  if (confirm('Make an error?')) BAD_CODE();
} catch (err) {
  console.log( 'catch' );
} finally {
  console.log( 'finally' );
}
1
2
3
4
5
6
7
8

提示

注意 try 中的局部变量。如果在 try 中声明变量(使用 let ),那么该变量只能在 try 中使用可见。 finally 中不可见。

  • try 中的 return

    try {
      return 1;
    } catch (err) {
      /* ... */
    } finally {
      console.log( 'finally' );
    }
    
    1
    2
    3
    4
    5
    6
    7

    此时,先执行 finally 中的代码,再执行 return

  • 只用 try...finally

    当不想再 try 结构中处理错误,但是要确保 finally 中的代码要执行:

    try{
      // ...
    } finally {
      // ...
    }
    
    1
    2
    3
    4
    5

    由于没有 catch ,所以 try 中的 error 总是会使代码执行跳转至函数 func() 外。但是,在跳出之前需要执行 finally 中的代码。

# 全局 catch

即使没有 try...catch ,大多数执行环境也允许设置全局错误处理程序来捕获 出错对象。在浏览器中,就是 window.onerror

📢 上次更新: 2022/09/02, 10:18:16