# 异常捕获
# 1、错误类型
# 1、常规运行时错误
let a;
console.log(a.length); // TypeError: Cannot read properties of undefined (reading 'length')
1
2
2
# 2、语法错误
const a; // The constant "b" must be initialized 
1
这种错误在代码编译阶段就会出问题。
# 3、异步中的错误
setTimeout(() => {
  let a;
  console.log(a.length)
}, 1000);
1
2
3
4
2
3
4
# 4、资源加载错误
<script src='https://www.testing.com/react'></script>
<img src="https://www.testing.com/picker.png" />
1
2
2
资源加载不到时的报错。
# 5、promise 的报错
new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(99);
  }, 1000);
}).then((val) => {
  console.log('val: ', val);
});
1
2
3
4
5
6
7
2
3
4
5
6
7
# 6、async/await中的错误
const val = await (async () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(99);
    }, 1000);
  });
})();
1
2
3
4
5
6
7
2
3
4
5
6
7
特别注意
- 1、Promise 的 reject 错误在没有被 reject 回调或者 catch 捕获到的时候才能被 unhandledrejection事件捕获;
- 2、Promise 中错误不能通过 try...catch的方式捕获;
- 3、async/await 中的错误 通过 try...catch的方式捕获, 也可以通过unhandledrejection事件捕获。
# 2、捕获异常的方式 - try/catch
- 1、常规运行时的错误;
- 2、async/await 中的异常(未被处理过);
- 3、async/await 中的 reject(未被处理过)。
# 3、捕获异常的方式 - window.onerror
window.onerror = (message, source, lineno, colno, error) => {
  console.log('message, source, lineno, colno, error: ', message, source, lineno, colno, error);
};
1
2
3
2
3
- 1、常规运行时的错误;
- 2、异步错误(宏任务 - setTimeout、setInterval);
# 4、捕获异常的方式 - error 事件
const handleError = (error) => {
  console.log('=======error: ', error);
};
window.addEventListener('error', handleError, true);
1
2
3
4
2
3
4
- 1、常规运行时的错误;
- 2、资源错误;
- 3、异步错误(宏任务 - setTimeout、setInterval);
# 5、捕获异常的方式 - unhandledrejection 事件
 const handleUnhandledrejection = (event) => {
    console.log('error=======: ', event);
    // event.preventDefault();
  };
window.addEventListener('unhandledrejection', handleUnhandledrejection);
1
2
3
4
5
2
3
4
5
前提是:未被reject回调或者catch接收;
- 1、Promise 中的异常;
- 2、Promise 中的 reject;
- 3、async/await 中的异常;
- 4、async/await 中的 reject。
# 6、总结
| 常规运行时错误 | 异步错误 | 资源加载错误 | Promise中的异常/reject | async/await中的异常/reject | |
|---|---|---|---|---|---|
| try/catch | √ | - | - | - | √ | 
| window.onerror | √ | √ | - | - | - | 
| error事件 | √ | √ | √ | - | - | 
| unhandledrejection 事件 | - | - | - | √ | √ | 
# 7、vue - errorCaptured 生命周期期
该生命周期会监听所有下级组件的错误,可以返回false阻止向上传播,可能会有多个上级节点都在监听错误。
errorCaptured(error, instance, info) {
  console.log('error, instance, info: ', error, instance, info);
}
1
2
3
2
3
# 8、vue - errorHandler
全局的错误监听,所有的组件的报错都会汇总到这里。 errorCaptured 返回false 则不会。
const app = createApp(App);
app.config.errorHandler = (error, instance, info) {
  console.log('error, instance, info: ', error, instance, info);
};
1
2
3
4
2
3
4
WARNING
errorhandler 会阻止错误走向 window.onerror。
# 9、react - ErrorBoundary
React 16+ 引入,可以监听所有下级组件的报错,同时降级展示UI。
ReactDom.render(
  <React.StrictMode>
    <ErrorBoundary>
      <App />
    </ErrorBoundary>
  </React.StrictMode>
)
1
2
3
4
5
6
7
2
3
4
5
6
7
