éçºããéãã¿ã¹ã¯ã§ä¸æããããªãå¯è½æ§ã®ããç¹å®ã®ç©äºãåæ ããããã«ãç¬èªã®ã¨ã©ã¼ã¯ã©ã¹ãå¿
è¦ã«ãªããã¨ãããããã¾ãããããã¯ã¼ã¯æä½ã®ã¨ã©ã¼ã§ããã°ãHttpErrorããã¼ã¿ãã¼ã¹æä½ã¯ DbErrorãæ¤ç´¢æä½ã®å ´åã¯NotFoundError ãªã©ãå¿
è¦ãªå ´åãããã¾ãã
ã¨ã©ã¼ã¯ message, name ãæã¾ãã㯠stack ã®ãããªåºæ¬ã®ã¨ã©ã¼ããããã£ããµãã¼ããã¹ãã§ããã§ãããä»ã«ãç¬èªã®ããããã£ãæã¤ããããã¾ãããä¾ãã° HttpError ãªãã¸ã§ã¯ãã§ããã°ã 404, 403 ããã㯠500 ã¨ãã£ãå¤ãã¨ã statusCode ããããã£ã§ãã
JavaScript ã¯ä»»æã®å¼æ°ã§ throw ã§ããã®ã§ãæè¡çã«ã¯ã«ã¹ã¿ã ã®ã¨ã©ã¼ã¯ã©ã¹ã¯ Error ããç¶æ¿ããå¿
è¦ã¯ããã¾ãããããããç¶æ¿ãã¦ããã¨ã¨ã©ã¼ãªãã¸ã§ã¯ããèå¥ãã obj instanceof Error ã使ããããã«ãªãã¾ãããã®ãããç¶æ¿ãã¦ããã»ãã®ããã¿ã¼ã§ãã
ã¢ããªã±ã¼ã·ã§ã³ãéçºããã«ã¤ããç¬èªã®ã¨ã©ã¼ãèªç¶ã«é層ãå½¢æãã¾ãããã¨ãã°ã HttpTimeoutError 㯠HttpError ãç¶æ¿ãããã¨ãã£ãããã«ã
Error ãæ¡å¼µãã
ä¾ã¨ãã¦ãã¦ã¼ã¶ãã¼ã¿ãã㤠JSON ãèªã颿° readUser(json) ãèãã¦ã¿ã¾ãããã
ããã§ã¯ãæå¹ãª json ãã©ã®ããã«è¦ãããã®ä¾ã示ãã¾ãã:
let json = `{ "name": "John", "age": 30 }`;
å
é¨çã«ã¯ãJSON.parse ã使ãã¾ãã䏿£ãª json ãåãåã£ãå ´å㯠SyntaxError ãã¹ãã¼ãã¾ãããããããã¨ã json ãæ§æçã«æ£ããã¦ãããããæ£ããã¦ã¼ã¶ã¨ã¯éãã¾ããããã® json ã«ã¯å¿
è¦ãªãã¼ã¿ãä¸è¶³ãã¦ããããããã¾ãããä¾ãã°ãä¸ã®ã±ã¼ã¹ã ã¨ãã¦ã¼ã¶ã«å¿
è¦ä¸å¯æ¬ 㪠name ã age ããããã£ãæã£ã¦ããªãå ´åã§ãã
ç§ãã¡ã®é¢æ° readUser(json) ã¯JSONãèªãã ãã§ãªãããã¼ã¿ã®ãã§ãã¯(ããªãã¼ã)ããã¾ããå¿
é ã®ãã£ã¼ã«ãããªãã£ããããã©ã¼ãããã誤ã£ã¦ããå ´åã¯ã¨ã©ã¼ã«ãªãã¾ããããã¦ãã㯠SyntaxError ã§ã¯ããã¾ããããªããªããã¼ã¿ã¯æ§æçã«ã¯æ£ãããå¥ã®ç¨®é¡ã®ã¨ã©ã¼ã ããã§ãããããã£ã¦ããã®ã¨ã©ã¼ã¯ ValidationError ã¨å¼ã³ããã®ããã®ã¯ã©ã¹ãä½ãã¾ãããããã®ãããªã¨ã©ã¼ã¯ãåé¡ã®ãããã£ã¼ã«ãã«é¢ããæ
å ±ãä¿æããå¿
è¦ãããã¾ãã
ValidationError ã¯ã©ã¹ã¯ Error ã¯ã©ã¹ããç¶æ¿ãã¾ãã
Error ã¯ã©ã¹ã¯çµã¿è¾¼ã¿ã§ãããããã§ã¯ä½ãæ¡å¼µãããã¨ãã¦ããã®ãçè§£ã§ããããããã®ã¯ã©ã¹ã®ããããã®ã³ã¼ãã示ãã¾ã:
// JavaScriptèªä½ã§å®ç¾©ãããçµã¿è¾¼ã¿ã®Errorã¯ã©ã¹ã®ãæ¬ä¼¼ã³ã¼ãã
class Error {
constructor(message) {
this.message = message;
this.name = "Error"; // (çµã¿è¾¼ã¿ã®ã¨ã©ã¼ã¯ã©ã¹ãã¨ã«ç°ãªãåå)
this.stack = <nested calls>; // 鿍æºã§ãããã»ã¨ãã©ã®ç°å¢ã¯ãµãã¼ããã¦ãã¾ã
}
}
ã§ã¯ã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) ã§è¦ªã®ã³ã³ã¹ãã©ã¯ã¿ãå¼ã³åºãã¦ãã¾ããJavaScriptã¯åã®ã³ã³ã¹ãã©ã¯ã¿å
ã§ super å¼ã³åºããå¿
è¦ã§ãããã¯ç¾©åã§ãã親ã®ã³ã³ã¹ãã©ã¯ã¿ã¯ message ããããã£ãã»ãããã¾ãã
親ã®ã³ã³ã¹ãã©ã¯ã¿ã¯ name ããããã£ãã"Error" ã¸ã»ãããã¾ãã®ã§ãè¡ (2) ã§æ£ããå¤ã«ãªã»ãããã¦ãã¾ãã
readUser(json) ã§ä½¿ã£ã¦ã¿ã¾ããã:
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
// Usage
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; // ç¥ããªãã¨ã©ã¼ãªã®ã§ãåã¹ãã¼ (**)
}
}
ä¸ã®ã³ã¼ãã® try..catch ãããã¯ã¯ ValidationError 㨠JSON.parse ããã®çµã¿è¾¼ã¿ã® SyntaxError 両æ¹ãå¦çãã¾ãã
è¡ (*) ã§ç¹å®ã®ã¨ã©ã¼ã®ç¨®é¡ããã§ãã¯ããããã«ãã©ã®ããã« instanceof ã使ã£ã¦ãããè¦ã¦ãã ããã
ãã®ããã«ã㦠err.name ãè¦ããã¨ãã§ãã¾ãã:
// ...
// (err instanceof SyntaxError) ã®ä»£ãã
} else if (err.name == "SyntaxError") { // (*)
// ...
instanceof ã®æ¹ããããã¿ã¼ã§ãããªããªããå°æ¥ ValidationError ãæ¡å¼µããPropertyRequiredError ã®ãããªãµãã¿ã¤ããä½ãããã§ãããã㦠instanceof ãã§ãã¯ã¯æ°ããç¶æ¿ããã¯ã©ã¹ã§ããã¾ãæ©è½ãç¶ãã¾ããããã¯å°æ¥ãä¿è¨¼ãã¾ãã
ã¾ããcatch ãæªç¥ã®ã¨ã©ã¼ã«ééããã¨ããè¡ (**) ã§ãããå度ã¹ãã¼ãããã¨ãéè¦ã§ãã catch ã¯ããªãã¼ã·ã§ã³ã¨æ§æã¨ã©ã¼ã®å¦çã®ä»æ¹ã ããç¥ã£ã¦ãã¾ããä»ã®ç¨®é¡(ã³ã¼ãä¸ã®ã¿ã¤ãããã®ä»)ã®å ´åã¯å¤±æãã¾ãã
ãããªãç¶æ¿
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; // ç¥ããªãã¨ã©ã¼ãªã®ã§ããããåã¹ãã¼
}
}
æ°ããã¯ã©ã¹ PropertyRequiredError ã¯ç°¡åã«ä½¿ãã¾ããããããã£åãæ¸¡ãã ãã§ãã: new PropertyRequiredError(property)ã人ãèªãã message ã¯ã³ã³ã¹ãã©ã¯ã¿ã§ä½ããã¾ãã
PropertyRequiredError ã³ã³ã¹ãã©ã¯ã¿ã§ã® this.name ã¯å度æåã§å²ãå½ã¦ããããã¨ã«æ³¨ç®ãã¦ãã ãããã«ã¹ã¿ã ã®ã¨ã©ã¼ãä½ã度㫠this.name = <class name> ã¨ä»£å
¥ãããã¨ã«ã¯ãå°ãããããããããããã¾ãããããthis.name = this.constructor.name ãè¡ã âåºæ¬ã¨ã©ã¼â ã¯ã©ã¹ãä½ããã«ã¹ã¿ã ã¨ã©ã¼ã¯ãããç¶æ¿ãããã¨ã§é¿ãããã¨ãã§ãã¾ãã
ããã MyError ã¨å¼ã³ã¾ãããã
ããã§ã¯ãåç´åãã MyError ã®ã³ã¼ãã¨ä»ã®ã«ã¹ã¿ã ã¨ã©ã¼ã¯ã©ã¹ã示ãã¾ãã:
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 is correct
alert( new PropertyRequiredError("field").name ); // PropertyRequiredError
ããã§ãã«ã¹ã¿ã ã¨ã©ã¼ã¯ã¯ããã«çããªãã¾ãããç¹ã« ValidationError ã¯ã³ã³ã¹ãã©ã¯ã¿ã® "this.name = ..." ã®è¡ãé¤ããã®ã§ã
ä¾å¤ã®ã©ããã³ã°
ä¸ã®ã³ã¼ãã®é¢æ° readUser ã®ç®ç㯠âã¦ã¼ã¶ãã¼ã¿ãèªããã¨â ã§ãããï¼ãã®å¦çã§ã¯ç°ãªã種é¡ã®ã¨ã©ã¼ãèµ·ããå¯è½æ§ãããã¾ããä»ã¯ SyntaxError 㨠ValidationError ãæã£ã¦ãã¾ãããå°æ¥ readUser 颿°ãæé·ããæ°ããªã³ã¼ããå¥ã®ç¨®é¡ã®ã¨ã©ã¼ãçã¿åºãããããã¾ããã
readUser ãå¼ã³åºãã³ã¼ãã¯ããããã®ã¨ã©ã¼ãå¦çããå¿
è¦ãããã¾ããä»ã¯ catch ãããã¯ã®ä¸ã§ãç°ãªãã¨ã©ã¼ã¿ã¤ãã®ãã§ãã¯ã¨æªç¥ã®ã¨ã©ã¼ãåã¹ãã¼ããããã«ãè¤æ°ã® if ã使ã£ã¦ãã¾ãã
ã¹ãã¼ãã¯ãã®ããã«ãªãã¾ã:
try {
...
readUser() // æ½å¨çãªã¨ã©ã¼ã®åå
...
} catch (err) {
if (err instanceof ValidationError) {
// ããªãã¼ã·ã§ã³ã¨ã©ã¼ã®å¦ç
} else if (err instanceof SyntaxError) {
// ã·ã³ã¿ãã¯ã¹ã¨ã©ã¼ã®å¦ç
} else {
throw err; // æªç¥ã®ã¨ã©ã¼ãåã¹ãã¼
}
}
ä¸ã®ã³ã¼ãã§ã¯2種é¡ã®ã¨ã©ã¼ãããã¾ãããä»ã«ããããã¾ãã
ãã readUser 颿°ãè¤æ°ã®ç¨®é¡ã®ã¨ã©ã¼ãçæããå ´åãreadUser å¼ã³åºãããããã¹ã¦ã®ã³ã¼ãã§ãæ¯åæ¬å½ã«ãã¹ã¦ã®ã¨ã©ã¼ã¿ã¤ãã1ã¤ãã¤ãã§ãã¯ãããã§ããï¼
å¤ãã®å ´åãçãã¯ãâãããâ ã§ãã:ãå¤å´ã®ã³ã¼ã㯠âããããã¹ã¦ã®1ã¤ä¸ã®ã¬ãã«â ã§ããããã§ããã¤ã¾ããâãã¼ã¿èªã¿è¾¼ã¿ã¨ã©ã¼â ãçºçãããã©ãããç¥ãããã ãã§ããçºçããæ£ç¢ºãªçç±ã«ã¤ãã¦ã¯ãå¤ãã®å ´åã¯ç¡é¢å¿ã§ãï¼ã¨ã©ã¼ã¡ãã»ã¼ã¸ã§èª¬æããã¦ãã¾ãï¼ãã¾ããããã«è¯ãã®ã¯ãå¿ è¦ãªå ´åã«ã®ã¿ã¨ã©ã¼ã®è©³ç´°ãåå¾ããæ¹æ³ããããã¨ã§ãã
ãã®ãã¯ããã¯ã¯ âä¾å¤ã®ã©ããã³ã°(wrapping exceptions)â ã¨å¼ã°ãã¾ãã
- æ±ç¨ç㪠âãã¼ã¿èªã¿è¾¼ã¿â ã¨ã©ã¼ã表ç¾ããæ°ããã¯ã©ã¹
ReadErrorãä½ãã¾ãã - 颿°
readUserã¯ValidationErrorãSyntaxErrorã®ãããªãå é¨ã§çºçãããã¼ã¿èªã¿è¾¼ã¿ã¨ã©ã¼ããã£ãããã代ããã«ReadErrorãçæãã¾ãã ReadErrorãªãã¸ã§ã¯ãã¯èªèº«ã®causeããããã£ã«å ã®ã¨ã©ã¼ã¸ã®åç §ãä¿æãã¾ãã
readUser ãå¼ã³åºãã³ã¼ãã¯ã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 ã¯èª¬æããã¦ããéãã«æ£ç¢ºã«åä½ãã¾ã â æ§æã¨ããªãã¼ã·ã§ã³ã¨ã©ã¼ããã£ããããReadError ã¨ã©ã¼ã代ããã«ã¹ãã¼ãã¾ã(æªç¥ã®ã¨ã©ã¼ã¯é常éãåã¹ãã¼ãã¾ã)ã
ãªã®ã§ãå¤é¨ã®ã³ã¼ã㯠instanceof ReadError ããã§ãã¯ããã ãã§ããå¯è½æ§ã®ãããã¹ã¦ã®ã¨ã©ã¼ã¿ã¤ãããªã¹ãããå¿
è¦ã¯ããã¾ããã
ãã®ã¢ããã¼ãã¯ãâä½ã¬ãã«ã®ä¾å¤â ãåãé¤ããå¼ã³åºãã³ã¼ãã§ä½¿ç¨ããããæ½è±¡çã§ä¾¿å©ãª âReadErrorâ ã« âã©ããâ ãããããâä¾å¤ã®ã©ããã³ã°â ã¨å¼ã°ãã¾ãã ãªãã¸ã§ã¯ãæåããã°ã©ãã³ã°ã§åºã使ç¨ããã¦ãã¾ãã
ãµããª
Errorãä»ã®çµã¿è¾¼ã¿ã®ã¨ã©ã¼ã¯ã©ã¹ããç¶æ¿ãããã¨ãã§ãã¾ãããã®ã¨ãã¯ãnameããããã£ã«æãå ¥ãããã¨ã¨ãsuperã®å¼ã³åºããå¿ããªãã§ãã ããã- ç¹å®ã®ã¨ã©ã¼ã®ãã§ãã¯ã«ã¯
instanceofã使ãã¾ããããã¯ç¶æ¿ãã¦ããå ´åã«ãæå¹ã§ããããããã¨ãã«ã¯ãµã¼ããã¼ãã£ã®ã©ã¤ãã©ãªããæ¥ãã¨ã©ã¼ãªãã¸ã§ã¯ããæã£ã¦ãã¦ãç°¡åã«ãã®ã¯ã©ã¹ãåå¾ããæ¹æ³ããªããã¨ãããã¾ãããã®ãããªå ´åã«ã¯nameããããã£ã使ãã¾ãã - ä¾å¤ã®ã©ããã³ã°ã¯åºãå©ç¨ããã¦ãããã¯ããã¯ã§ã: 颿°ãä½ã¬ãã«ã®ä¾å¤ãå¦çããããããã®ä½ã¬ãã«ã®ä¾å¤ã®ä»£ããã«é«ã¬ãã«ã®ã¨ã©ã¼ãçæãã¾ããä½ã¬ãã«ã®ä¾å¤ã¯ãä¸ã®ä¾ã®
err.causeã®ããã«ãªãã¸ã§ã¯ãã®ããããã£ã«ãªããã¨ãããã¾ãããå³å¯ã«ã¯å¿ é ã§ã¯ããã¾ããã
ã³ã¡ã³ã
<code>ã¿ã°ã使ã£ã¦ãã ãããè¤æ°è¡ã®å ´åã¯<pre>ãã10è¡ãè¶ ããå ´åã«ã¯ãµã³ãããã¯ã¹ã使ã£ã¦ãã ãã(plnkr, JSBin, codepenâ¦)ã