什么是异常
Error objects are thrown when runtime errors occur. The Error object can also be used as a base object for user-defined exceptions.
描述的很简单,我们总结一下就是代码在执行过程中遇到了问题,程序已经无法正常运行了,Error对象会被抛出,这一点它不同于大部分编程语言里使用的异常对象Exception,甚至更适合称之为错误,应该说事实也确实如此,Error对象在未被抛出时候和js里其他的普通对象没有任何差别是不会引发异常的,同时Error 对象也可用于用户自定义错误的基础对象。
try { const 123variable = 2;} catch(e) { console.log('捕获到了:', e)}
<script> function throwSomeError() { throw new Error('抛个异常玩玩'); console.log('我估计是凉了,不会执行我了!'); }
throwSomeError(); console.log('那么我呢?')</script>
<script> console.log('大家猜猜我会执行吗?');</script>
异常的类型
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取分页数据const getPagedData = (pageIndex, pageSize) => {if(pageIndex < 0 || pageSize < 0 || pageSize > 1000) {throw new RangeError(`pageIndex 必须大于0, pageSize必须在0和1000之间`);}return [];}// 转换时间格式const dateFormat = (dateObj) => {if(dateObj instanceof Date) {return 'formated date string';}throw new TypeError('传入的日期类型错误');}
new Error('出错了!');console.log('我吃嘛嘛香,喝嘛嘛棒!'); // 正常输出 '我吃嘛嘛香,喝嘛嘛棒!'
// badthrow '出错了';throw 123;throw [];throw null;
异常捕获
try { // 要运行的代码,可能引发异常 doSomethingMightThrowError();} catch (error) { // 处理异常的代码块,当发生异常时将会被捕获,如果不继续throw则不会再向上传播 // error为捕获的异常对象 // 这里一般能让程序恢复的代码 doRecovery();}finally { // 无论是否出现异常,始终都会执行的代码 doFinally();}
// Timeouttry { setTimeout(() => { throw Error("定时器出错了!"); }, 1000);} catch (error) { console.error(error.message);}
// Eventstry { window.addEventListener("click", function() { throw Error("点击事件出错了!"); });} catch (error) { console.error(error.message);}
const promiseA = new Promise((resolve,reject)=>{ throw new Error('Promise出错了!');});
const doSomethingWhenResolve = () => {};
const doSomethingWhenReject = (error) => { logger.log(error)}
// 使用catch捕获const promiseB = promiseA.then(doSomethingWhenResolve).catch(doSomethingWhenReject);// 等价于const promiseB = promise.then(doSomethingWhenResolve, doSomethingWhenResolve);
promiseB.then(() => { console.log('我又可以正常进到then方法了!');}).catch(()=>{ console.log('不会来这里!');})
Prefer Exceptions to Returning Error Codes
1、业务流程更加清晰易读,我们把异常和业务流程理解为两个不同的问题,可以分开去处理;
2、分开来的两个逻辑都更加聚焦,代码更简洁;
// Dirtyclass Laptop { sendShutDown() { const deviceID = getID(DEVICE_LAPTOP); if (deviceID !== DEVICE_STATUS.INVALID) { pauseDevice(deviceID); clearDeviceWorkQueue(deviceID); closeDevice(deviceID); } else { logger.log('Invalid handle for: ' + DEVICE_LAPTOP.toString()); } } getID(status) { ... // 总是会返回deviceID,无论是不是合法有效的 return deviceID; }}// Cleanclass Laptop { sendShutDown() { try { tryToShutDown(); } catch (error) { logger.log(error); } } tryToShutDown() { const deviceID = getID(DEVICE_LAPTOP); pauseDevice(deviceID); clearDeviceWorkQueue(deviceID); closeDevice(deviceID); }
getID(status) { ... throw new DeviceShutDownError('Invalid handle for: ' + deviceID.toString()); ... return deviceID; }}
Don't ignore caught error!
// badtry { doSomethingMightThrowError();} catch (error) { console.log(error);}
// goodtry { doSomethingMightThrowError();} catch (error){ console.error(error); message.error(error.message); logger.log(error);}
Don't ignore rejected promises!
// badfetchData().then(doSomethingMightThrowError).catch(console.log);
// goodfetchData() .then(doSomethingMightThrowError) .catch(error => { console.error(error); message.error(error.message); logger.log(error); });
Exceptions Hierarchy
export class RequestException extends Error { constructor(message) { super(`RequestException: ${mesage}`); }}
export class AccountException extends Error { constructor(message) { super(`AccountException: ${message}`); }}
const AccountController = { getAccount: (id) => { ... throw new RequestException('请求账户信息失败!'); ... }}
// 客户端代码,创建账户const id = 1;const account = AccountController.getAccount(id);if(account){ throw new AccountException('账户已存在!');}
Provide context with exceptions
错误边界是一种 React 组件,这种组件可以捕获发生在其子组件树任何位置的 JavaScript 错误,并打印这些错误,同时展示降级 UI,而并不会渲染那些发生崩溃的子组件树。错误边界可以捕获发生在整个子组件树的渲染期间、生命周期方法以及构造函数中的错误。
import { Result } from 'antd';import type { ErrorInfo } from 'react';import React from 'react';
// eslint-disable-next-line @typescript-eslint/ban-typesclass ErrorBoundary extends React.Component< { children?: React.ReactNode }, { hasError: boolean; errorInfo: string }> { state = { hasError: false, errorInfo: '' };
static getDerivedStateFromError(error: Error) { return { hasError: true, errorInfo: error.message }; }
componentDidCatch(error: any, errorInfo: ErrorInfo) { // You can also log the error to an error reporting service // eslint-disable-next-line no-console console.log(error, errorInfo); }
render() { if (this.state.hasError) { // You can render any custom fallback UI return <Result status="error" title="Something went wrong." extra={this.state.errorInfo} />; } return this.props.children; }}
export { ErrorBoundary };
window.onerror事件
// message:错误信息(字符串)。// source:发生错误的脚本URL(字符串)// lineno:发生错误的行号(数字)// colno:发生错误的列号(数字)// error:Error对象(对象)window.onerror = function(message, source, lineno, colno, error) { logger.log('捕获到异常:',{ message, source, lineno, colno, error });}
unhandledrejection事件
window.addEventListener('unhandledrejection', (e) => { console.error('catch', e) }, true)
1、将面向开发的异常信息转换成更友好的用户界面提示;
参考链接:
[1]https://developer.mozilla.org/zh-CN/Core_JavaScript_1.5_Reference/Global_Functions/eval
[2]https://reactjs.org/docs/error-boundaries.html
往期推荐
《Java工程师必读手册》
工匠追求“术”到极致,其实就是在寻“道”,且离悟“道”也就不远了,亦或是已经得道,这就是“工匠精神”——一种追求“以术得道”的精神。 如果一个工匠只满足于“术”,不能追求“术”到极致去悟“道”,那只是一个靠“术”养家糊口的工匠而已。作者根据多年来的实践探索,总结了大量的Java编码之“术”,试图阐述出心中的Java编码之“道”。
点击阅读原文查看详情。