彿们å¨å¼åæäºä¸è¥¿æ¶ï¼ç»å¸¸ä¼éè¦æä»¬èªå·±ç error ç±»æ¥åæ 卿们çä»»å¡ä¸å¯è½åºéçç¹å®ä»»å¡ã对äºç½ç»æä½ä¸ç errorï¼æä»¬éè¦ HttpErrorï¼å¯¹äºæ°æ®åºæä½ä¸ç errorï¼æä»¬éè¦ DbErrorï¼å¯¹äºæç´¢æä½ä¸ç errorï¼æä»¬éè¦ NotFoundErrorï¼ççã
æä»¬èªå®ä¹ç error åºè¯¥æ¯æåºæ¬ç error ç屿§ï¼ä¾å¦ messageï¼nameï¼å¹¶ä¸æå¥½è¿æ stackã使¯å®ä»¬ä¹å¯è½ä¼æå
¶ä»å±äºå®ä»¬èªå·±ç屿§ï¼ä¾å¦ï¼HttpError 对象å¯è½ä¼æä¸ä¸ª statusCode 屿§ï¼å±æ§å¼å¯è½ä¸º 404ã403 æ 500 çã
JavaScript å
è®¸å° throw ä¸ä»»ä½åæ°ä¸èµ·ä½¿ç¨ï¼æä»¥ä»ææ¯ä¸è®²ï¼æä»¬èªå®ä¹ç error ä¸éè¦ä» Error ä¸ç»§æ¿ã使¯ï¼å¦ææä»¬ç»§æ¿ï¼é£ä¹å°±å¯ä»¥ä½¿ç¨ obj instanceof Error æ¥è¯å« error 对象ãå æ¤ï¼æå¥½ç»§æ¿å®ã
éçå¼åçåºç¨ç¨åºçå¢é¿ï¼æä»¬èªå·±ç error èªç¶ä¼å½¢æå½¢æä¸ä¸ªå±æ¬¡ç»æï¼hierarchyï¼ãä¾å¦ï¼HttpTimeoutError å¯è½ç»§æ¿èª HttpErrorï¼ççã
æ©å± Error
ä¾å¦ï¼è®©æä»¬èèä¸ä¸ªå½æ° readUser(json)ï¼è¯¥å½æ°åºè¯¥è¯»å带æç¨æ·æ°æ®ç JSONã
è¿éæ¯ä¸ä¸ªå¯ç¨ç json çä¾åï¼
let json = `{ "name": "John", "age": 30 }`;
å¨å½æ°å
é¨ï¼æä»¬å°ä½¿ç¨ JSON.parseã妿宿¥æ¶å°æ ¼å¼ä¸æ£ç¡®ç jsonï¼å°±ä¼æåº SyntaxErrorã使¯ï¼å³ä½¿ json å¨è¯æ³ä¸æ¯æ£ç¡®çï¼ä¹ä¸æå³çè¯¥æ°æ®æ¯ææçç¨æ·æ°æ®ï¼å¯¹å§ï¼å 为å®å¯è½ä¸¢å¤±äºæäºå¿
è¦çæ°æ®ãä¾å¦ï¼å¯¹ç¨æ·æ¥è¯´ï¼å¿
ä¸å¯å°çæ¯ name å age 屿§ã
æä»¬ç彿° readUser(json) ä¸ä»
ä¼è¯»å JSONï¼è¿ä¼æ£æ¥ï¼âéªè¯âï¼æ°æ®ãå¦ææ²¡ææå¿
é¡»çåæ®µï¼æè
ï¼å段çï¼æ ¼å¼é误ï¼é£ä¹å°±ä¼åºç°ä¸ä¸ª errorãå¹¶ä¸è¿äºå¹¶ä¸æ¯ SyntaxErrorï¼å 为è¿äºæ°æ®å¨è¯æ³ä¸æ¯æ£ç¡®çï¼è¿äºæ¯å¦ä¸ç§é误ãæä»¬ç§°ä¹ä¸º ValidationErrorï¼å¹¶ä¸ºä¹å建ä¸ä¸ªç±»ãè¿ç§ç±»åçé误ä¹åºè¯¥å
嫿å
³è¿è§å段çä¿¡æ¯ã
æä»¬ç ValidationError ç±»åºè¯¥ç»§æ¿èª Error ç±»ã
Error ç±»æ¯å
建çï¼ä½æä»¬å¯ä»¥éè¿ä¸é¢è¿æ®µè¿ä¼¼ä»£ç çè§£æä»¬è¦æ©å±çå
容ï¼
// JavaScript èªèº«å®ä¹çå
建ç Error ç±»çâ伪代ç â
class Error {
constructor(message) {
this.message = message;
this.name = "Error"; // (ä¸åçå
建 error ç±»æä¸åçåå)
this.stack = <call stack>; // éæ åçï¼ä½å¤§å¤æ°ç¯å¢é½æ¯æå®
}
}
ç°å¨è®©æä»¬ä»å
¶ä¸ç»§æ¿ ValidationError è¯ä¸è¯ï¼
class ValidationError extends Error {
constructor(message) {
super(message); // (1)
this.name = "ValidationError"; // (2)
}
}
function test() {
throw new ValidationError("Whoops!");
}
try {
test();
} catch(err) {
alert(err.message); // Whoops!
alert(err.name); // ValidationError
alert(err.stack); // ä¸ä¸ªåµå¥è°ç¨çåè¡¨ï¼æ¯ä¸ªè°ç¨é½æå¯¹åºçè¡å·
}
请注æï¼å¨ (1) è¡ä¸æä»¬è°ç¨äºç¶ç±»ç constructorãJavaScript è¦æ±æä»¬å¨åç±»ç constructor ä¸è°ç¨ superï¼æä»¥è¿æ¯å¿
é¡»çãç¶ç±»ç constructor è®¾ç½®äº message 屿§ã
ç¶ç±»ç constructor è¿å° name 屿§çå¼è®¾ç½®ä¸ºäº "Error"ï¼æä»¥å¨ (2) è¡ä¸ï¼æä»¬å°å
¶é置为äºå³è¾¹çå¼ã
让æä»¬å°è¯å¨ readUser(json) ä¸ä½¿ç¨å®å§ï¼
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
// ç¨æ³
function readUser(json) {
let user = JSON.parse(json);
if (!user.age) {
throw new ValidationError("No field: age");
}
if (!user.name) {
throw new ValidationError("No field: name");
}
return user;
}
// try..catch çå·¥ä½ç¤ºä¾
try {
let user = readUser('{ "age": 25 }');
} catch (err) {
if (err instanceof ValidationError) {
alert("Invalid data: " + err.message); // Invalid data: No field: name
} else if (err instanceof SyntaxError) { // (*)
alert("JSON Syntax Error: " + err.message);
} else {
throw err; // æªç¥ç errorï¼å次æåº (**)
}
}
ä¸é¢ä»£ç ä¸ç try..catch 忢å¤çæä»¬ç ValidationError åå¤çæ¥èª JSON.parse çå
建 SyntaxErrorã
请çä¸ä¸æä»¬æ¯å¦ä½ä½¿ç¨ instanceof æ¥æ£æ¥ (*) è¡ä¸çç¹å®é误类åçã
æä»¬ä¹å¯ä»¥çç err.nameï¼åè¿æ ·ï¼
// ...
// instead of (err instanceof SyntaxError)
} else if (err.name == "SyntaxError") { // (*)
// ...
ä½¿ç¨ instanceof ççæ¬è¦å¥½å¾å¤ï¼å ä¸ºå°æ¥æä»¬ä¼å¯¹ ValidationError è¿è¡æ©å±ï¼å建å®çåç±»åï¼ä¾å¦ PropertyRequiredErrorãè instanceof æ£æ¥å¯¹äºæ°çç»§æ¿ç±»ä¹éç¨ãæä»¥è¿æ¯é¢åæªæ¥çåæ³ã
è¿æä¸ç¹å¾éè¦ï¼å¨ catch éå°äºæªç¥çé误ï¼å®ä¼å¨ (**) è¡å°è¯¥éè¯¯åæ¬¡æåºãcatch ååªç¥éå¦ä½å¤ç validation é误åè¯æ³é误ï¼èå
¶ä»é误ï¼ç±ä»£ç ä¸çæ¼åé误æå
¶ä»æªç¥åå 导è´çï¼åºè¯¥è¢«æåºï¼fall throughï¼ã
æ·±å ¥ç»§æ¿
ValidationError ç±»æ¯é常éç¨çãå¾å¤ä¸è¥¿é½å¯è½åºéã对象ç屿§å¯è½ç¼ºå¤±æè
屿§å¯è½ææ ¼å¼é误ï¼ä¾å¦ age 屿§çå¼ä¸ºä¸ä¸ªå符串è䏿¯æ°åï¼ã让æä»¬é对缺å°å±æ§çé误æ¥å¶ä½ä¸ä¸ªæ´å
·ä½ç PropertyRequiredError ç±»ãå®å°æºå¸¦æå
³ç¼ºå°ç屿§çç¸å
³ä¿¡æ¯ã
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
class PropertyRequiredError extends ValidationError {
constructor(property) {
super("No property: " + property);
this.name = "PropertyRequiredError";
this.property = property;
}
}
// ç¨æ³
function readUser(json) {
let user = JSON.parse(json);
if (!user.age) {
throw new PropertyRequiredError("age");
}
if (!user.name) {
throw new PropertyRequiredError("name");
}
return user;
}
// try..catch çå·¥ä½ç¤ºä¾
try {
let user = readUser('{ "age": 25 }');
} catch (err) {
if (err instanceof ValidationError) {
alert("Invalid data: " + err.message); // Invalid data: No property: name
alert(err.name); // PropertyRequiredError
alert(err.property); // name
} else if (err instanceof SyntaxError) {
alert("JSON Syntax Error: " + err.message);
} else {
throw err; // æªç¥ errorï¼å°å
¶å次æåº
}
}
è¿ä¸ªæ°çç±» PropertyRequiredError 使ç¨èµ·æ¥å¾ç®åï¼æä»¬åªéè¦ä¼ é屿§åï¼new PropertyRequiredError(property)ã人类å¯è¯»ç message æ¯ç± constructor çæçã
请注æï¼å¨ PropertyRequiredError constructor ä¸ç this.name æ¯éè¿æå¨éæ°èµå¼çãè¿å¯è½ä¼å徿äºä¹å³ ââ 卿¯ä¸ªèªå®ä¹ error ç±»ä¸é½è¦è¿è¡ this.name = <class name> èµå¼æä½ãæä»¬å¯ä»¥éè¿å建èªå·±çâåºç¡é误ï¼basic errorï¼âç±»æ¥é¿å
è¿ç§æ
åµï¼è¯¥ç±»è¿è¡äº this.name = this.constructor.name èµå¼ãç¶åè®©æææä»¬èªå®ä¹ç error é½ä»è¿ä¸ªâåºç¡é误âç±»è¿è¡ç»§æ¿ã
让æä»¬ç§°ä¹ä¸º MyErrorã
è¿æ¯å¸¦æ MyError 以åå
¶ä»èªå®ä¹ç error ç±»ç代ç ï¼å·²è¿è¡ç®åï¼
class MyError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
}
}
class ValidationError extends MyError { }
class PropertyRequiredError extends ValidationError {
constructor(property) {
super("No property: " + property);
this.property = property;
}
}
// name æ¯å¯¹ç
alert( new PropertyRequiredError("field").name ); // PropertyRequiredError
ç°å¨èªå®ä¹ç error çäºå¾å¤ï¼ç¹å«æ¯ ValidationErrorï¼å 为æä»¬æè±äº constructor ä¸ç "this.name = ..." è¿ä¸è¡ã
å è£ å¼å¸¸
å¨ä¸é¢ä»£ç ä¸ç彿° readUser çç®çå°±æ¯â读åç¨æ·æ°æ®âãå¨è¿ä¸ªè¿ç¨ä¸å¯è½ä¼åºç°ä¸åç±»åç errorãç®åæä»¬æäº SyntaxError å ValidationErrorï¼ä½æ¯å°æ¥ï¼å½æ° readUser å¯è½ä¼ä¸æå£®å¤§ï¼å¹¶å¯è½ä¼äº§çå
¶ä»ç±»åç errorã
è°ç¨ readUser ç代ç åºè¯¥å¤çè¿äº errorãç°å¨å®å¨ catch åä¸ä½¿ç¨äºå¤ä¸ª if è¯å¥æ¥æ£æ¥ error ç±»ï¼å¤çå·²ç¥ç errorï¼å¹¶å次æåºæªç¥ç errorã
è¯¥æ¹æ¡æ¯è¿æ ·çï¼
try {
...
readUser() // æ½å¨ç error æº
...
} catch (err) {
if (err instanceof ValidationError) {
// å¤ç validation error
} else if (err instanceof SyntaxError) {
// å¤ç syntax error
} else {
throw err; // æªç¥ errorï¼å次æåºå®
}
}
å¨ä¸é¢ç代ç ä¸ï¼æä»¬å¯ä»¥çå°ä¸¤ç§ç±»åç errorï¼ä½æ¯å¯ä»¥ææ´å¤ã
妿 readUser 彿°ä¼äº§çå¤ç§ errorï¼é£ä¹æä»¬åºè¯¥é®é®èªå·±ï¼æä»¬æ¯å¦ççæ³æ¯æ¬¡é½ä¸ä¸æ£æ¥ææç error ç±»åï¼
éå¸¸çæ¡æ¯ âNoâï¼æä»¬å¸æè½å¤âæ¯å®é«ä¸ä¸ªçº§å«âãæä»¬åªæ³ç¥éè¿éæ¯å¦æ¯âæ°æ®è¯»åå¼å¸¸â ââ 为ä»ä¹åçäºè¿æ ·ç error éå¸¸æ¯æ å ³ç´§è¦çï¼error ä¿¡æ¯æè¿°äºå®ï¼ãæè ï¼å¦ææä»¬æä¸ç§æ¹å¼è½å¤è·å error ç详ç»ä¿¡æ¯é£å°±æ´å¥½äºï¼ä½åææ¯æä»¬éè¦ã
æä»¬ææè¿°çè¿é¡¹ææ¯è¢«ç§°ä¸ºâå è£ å¼å¸¸âã
- æä»¬å°å建ä¸ä¸ªæ°çç±»
ReadErroræ¥è¡¨ç¤ºä¸è¬çâæ°æ®è¯»åâ errorã - 彿°
readUserå°æè·å é¨åççæ°æ®è¯»å errorï¼ä¾å¦ValidationErroråSyntaxErrorï¼å¹¶çæä¸ä¸ªReadErroræ¥è¿è¡æ¿ä»£ã - 对象
ReadError伿坹åå§ error çå¼ç¨ä¿åå¨å ¶cause屿§ä¸ã
ä¹åï¼è°ç¨ readUser ç代ç åªéè¦æ£æ¥ ReadErrorï¼èä¸å¿
æ£æ¥æ¯ç§æ°æ®è¯»å errorãå¹¶ä¸ï¼å¦æéè¦æ´å¤ error ç»èï¼é£ä¹å¯ä»¥æ£æ¥ ReadError 对象ç cause 屿§ã
ä¸é¢ç代ç å®ä¹äº ReadErrorï¼å¹¶å¨ readUser å try..catch 䏿¼ç¤ºäºå
¶ç¨æ³ï¼
class ReadError extends Error {
constructor(message, cause) {
super(message);
this.cause = cause;
this.name = 'ReadError';
}
}
class ValidationError extends Error { /*...*/ }
class PropertyRequiredError extends ValidationError { /* ... */ }
function validateUser(user) {
if (!user.age) {
throw new PropertyRequiredError("age");
}
if (!user.name) {
throw new PropertyRequiredError("name");
}
}
function readUser(json) {
let user;
try {
user = JSON.parse(json);
} catch (err) {
if (err instanceof SyntaxError) {
throw new ReadError("Syntax Error", err);
} else {
throw err;
}
}
try {
validateUser(user);
} catch (err) {
if (err instanceof ValidationError) {
throw new ReadError("Validation Error", err);
} else {
throw err;
}
}
}
try {
readUser('{bad json}');
} catch (e) {
if (e instanceof ReadError) {
alert(e);
// Original error: SyntaxError: Unexpected token b in JSON at position 1
alert("Original error: " + e.cause);
} else {
throw e;
}
}
å¨ä¸é¢ç代ç ä¸ï¼readUser æ£å¦ææè¿°ç飿 ·æ£å¸¸å·¥ä½ ââ æè·è¯æ³åéªè¯ï¼validationï¼é误ï¼å¹¶æåº ReadErrorï¼å¯¹äºæªç¥é误å°ç
§å¸¸å次æåºï¼ã
æä»¥å¤é¨ä»£ç æ£æ¥ instanceof ReadErrorï¼å¹¶ä¸å®çç¡®æ¯ãä¸å¿
ååºææå¯è½ç error ç±»åã
è¿ç§æ¹æ³è¢«ç§°ä¸ºâå
è£
å¼å¸¸ï¼wrapping exceptionsï¼âï¼å 为æä»¬å°âä½çº§å«âçå¼å¸¸âå
è£
âå°äºæ´æ½è±¡ç ReadError ä¸ãå®è¢«å¹¿æ³åºç¨äºé¢å对象çç¼ç¨ä¸ã
æ»ç»
- æä»¬å¯ä»¥æ£å¸¸å°ä»
Erroråå ¶ä»å 建ç error ç±»ä¸è¿è¡ç»§æ¿ãæä»¬åªéè¦æ³¨æname屿§ä»¥åä¸è¦å¿äºè°ç¨superã - æä»¬å¯ä»¥ä½¿ç¨
instanceofæ¥æ£æ¥ç¹å®ç errorãä½ææ¶æä»¬ææ¥èªç¬¬ä¸æ¹åºç error 对象ï¼å¹¶ä¸å¨è¿å¿æ²¡æç®åçæ¹æ³æ¥è·åå®çç±»ãé£ä¹å¯ä»¥å°name屿§ç¨äºè¿ä¸ç±»çæ£æ¥ã - å
è£
å¼å¸¸æ¯ä¸é¡¹å¹¿æ³åºç¨çææ¯ï¼ç¨äºå¤çä½çº§å«å¼å¸¸å¹¶å建é«çº§å« error è䏿¯åç§ä½çº§å« error ç彿°ãå¨ä¸é¢ç示ä¾ä¸ï¼ä½çº§å«å¼å¸¸ææ¶ä¼æä¸ºè¯¥å¯¹è±¡ç屿§ï¼ä¾å¦
err.causeï¼ä½è¿ä¸æ¯ä¸¥æ ¼è¦æ±çã
è¯è®º
<code>æ ç¾æå ¥åªæå 个è¯ç代ç ï¼æå ¥å¤è¡ä»£ç å¯ä»¥ä½¿ç¨<pre>æ ç¾ï¼å¯¹äºè¶ è¿ 10 è¡ç代ç ï¼å»ºè®®ä½ ä½¿ç¨æ²ç®±ï¼plnkrï¼JSBinï¼codepenâ¦ï¼