你将如何实现不同类型的错误,这样你就能捕捉到特定错误并让其他人冒出来......?
实现此目的的一种方法是修改Error
对象的原型:
Error.prototype.sender = "";
function throwSpecificError()
{
var e = new Error();
e.sender = "specific";
throw e;
}
捕获特定错误:
try
{
throwSpecificError();
}
catch (e)
{
if (e.sender !== "specific") throw e;
// handle specific error
}
你们有其他选择吗?
答案 0 :(得分:120)
要创建自定义例外,您可以从Error对象继承:
function SpecificError () {
}
SpecificError.prototype = new Error();
// ...
try {
throw new SpecificError;
} catch (e) {
if (e instanceof SpecificError) {
// specific error
} else {
throw e; // let others bubble up
}
}
没有继承自Error的简约方法可能是抛出一个具有名称和消息属性的简单对象:
function throwSpecificError() {
throw {
name: 'SpecificError',
message: 'SpecificError occurred!'
};
}
// ...
try {
throwSpecificError();
} catch (e) {
if (e.name == 'SpecificError') {
// specific error
} else {
throw e; // let others bubble up
}
}
答案 1 :(得分:14)
如下面的评论中所述,这是特定于Mozilla的,但您可以使用'条件捕获'块。 e.g:
try {
...
throwSpecificError();
...
}
catch (e if e.sender === "specific") {
specificHandler(e);
}
catch (e if e.sender === "unspecific") {
unspecificHandler(e);
}
catch (e) {
// don't know what to do
throw e;
}
这更类似于Java中使用的类型化异常处理,至少在语法上如此。
答案 2 :(得分:8)
try-catch-finally.js
_try(function () {
throw 'My error';
})
.catch(Error, function (e) {
console.log('Caught Error: ' + e);
})
.catch(String, function (e) {
console.log('Caught String: ' + e);
})
.catch(function (e) {
console.log('Caught other: ' + e);
})
.finally(function () {
console.log('Error was caught explicitly');
});
答案 3 :(得分:1)
出口使用模块
load_data()
导入脚本:
/**
* Custom InputError
*/
class InputError extends Error {
/**
* Create InputError
* @param {String} message
*/
constructor(message) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
/**
* Custom AuthError
*/
class AuthError extends Error {
/**
* Create AuthError
* @param {String} message
*/
constructor(message) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
/**
* Custom NotFoundError
*/
class NotFoundError extends Error {
/**
* Create NotFoundError
* @param {String} message
*/
constructor(message) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
module.exports = {
InputError: InputError,
AuthError: AuthError,
NotFoundError: NotFoundError
};
使用:
const {InputError, AuthError, NotFoundError} = require(path.join(process.cwd(), 'lib', 'errors'));
外部调用代码:
function doTheCheck = () =>
checkInputData().then(() => {
return Promise.resolve();
}).catch(err => {
return Promise.reject(new InputError(err));
});
};
答案 4 :(得分:0)
我不喜欢上述任何一种解决方案,所以我自己做了。 try-catch-finally.js非常酷,只是如果您在尝试之前忘记了一个下划线(_),那么代码仍然可以正常运行,但是任何东西都不会被捕获!好吧。
我在代码中添加了一个CatchFilter:
"use strict";
/**
* This catches a specific error. If the error doesn't match the errorType class passed in, it is rethrown for a
* different catch handler to handle.
* @param errorType The class that should be caught
* @param funcToCall The function to call if an error is thrown of this type
* @return {Function} A function that can be given directly to the `.catch()` part of a promise.
*/
module.exports.catchOnly = function(errorType, funcToCall) {
return (error) => {
if(error instanceof errorType) {
return funcToCall(error);
} else {
// Oops, it's not for us.
throw error;
}
};
};
现在我可以像在C#或Java中那样进行过滤了:
new Promise((resolve, reject => {
<snip><snip>
}).catch(CatchFilter.catchOnly(MyError, err =>
console.log("This is for my error");
}).catch(err => {
console.log("This is for all of the other errors.");
});
答案 5 :(得分:0)
不幸的是,没有“官方”的方式可以在 Javascript 中实现这个基本功能。我将分享我在不同包中看到的三种最常见的解决方案,以及如何在现代 Javascript (es6+) 中实现它们,以及它们的一些优缺点。
在 es6 中对“Error”的实例进行子类化变得更加容易。只需执行以下操作:
class FileNotFoundException extends Error {
constructor(message) {
super(message)
// Not required, but makes uncaught error messages nicer.
this.name = 'FileNotFoundException'
}
}
完整示例:
class FileNotFoundException extends Error {
constructor(message) {
super(message)
// Not required, but makes uncaught error messages nicer.
this.name = 'FileNotFoundException'
}
}
// Example usage
function readFile(path) {
throw new FileNotFoundException(`The file ${path} was not found`)
}
try {
readFile('./example.txt')
} catch (err) {
if (err instanceof FileNotFoundException) {
// Handle the custom exception
console.log(`Could not find the file. Reason: ${err.message}`)
} else {
// Rethrow it - we don't know how to handle it
// The stacktrace won't be changed, because
// that information is attached to the error
// object when it's first constructed.
throw err
}
}
如果您不喜欢将 this.name
设置为硬编码字符串,您可以将其设置为 this.constructor.name
,这将给出您的类的名称。这样做的好处是您的自定义异常的任何子类都不需要更新 this.name
,因为 this.constructor.name
将是子类的名称。
与某些替代解决方案相比,子类异常的优势在于它们可以提供更好的编辑器支持(例如自动完成)。您可以轻松地向特定异常类型添加自定义行为,例如附加函数、替代构造函数参数等。在提供自定义行为或数据时,支持 typescript 也往往更容易。
有很多关于如何正确子类化 Error
的讨论。例如,如果您使用的是转译器,上述解决方案可能不起作用。有些人建议使用特定于平台的 captureStackTrace() 如果它可用(虽然我在使用它时没有注意到错误有任何不同 - 也许它不再相关了?♂️)。要了解更多信息,请参阅 this MDN 页面和 This Stackoverflow 答案。
许多浏览器 API 都走这条路并抛出自定义异常(如 here 所示)
这个想法很简单。创建您的错误,在您的错误中添加一个额外的属性,例如“代码”,然后抛出它。
const error = new Error(`The file ${path} was not found`)
error.code = 'NotFound'
throw error
完整示例:
function readFile(path) {
const error = new Error(`The file ${path} was not found`)
error.code = 'NotFound'
throw error
}
try {
readFile('./example.txt')
} catch (err) {
if (err.code === 'NotFound') {
console.log(`Could not find the file. Reason: ${err.message}`)
} else {
throw err
}
}
当然,您可以创建一个辅助函数来删除一些样板并确保一致性。
此解决方案的优点是您无需导出包可能引发的所有可能异常的列表。您可以想象,例如,如果您的包一直使用 NotFound 异常来指示特定函数无法找到预期资源,那会变得多么尴尬。您想添加一个 addUserToGroup() 函数,该函数理想情况下会根据未找到的资源抛出 UserNotFound 或 GroupNotFound 异常。对于子类异常,您将不得不做出棘手的决定。使用错误对象上的代码,您就可以做到。
这是路由节点的 fs 模块采取的异常。如果您尝试读取一个不存在的文件,它会抛出一个带有一些附加属性的错误实例,例如 code
,它会针对该特定异常将其设置为 "ENOENT"
。
谁说你必须扔掉它们?在某些情况下,只返回出错的地方可能最有意义。
function readFile(path) {
if (itFailed()) {
return { exCode: 'NotFound' }
} else {
return { data: 'Contents of file' }
}
}
在处理大量异常时,像这样的解决方案可能最有意义。这样做很简单,并且可以帮助自我记录哪些函数给出了哪些异常,这使得代码更加健壮。缺点是它会给你的代码增加很多膨胀。
完整示例:
function readFile(path) {
if (Math.random() > 0.5) {
return { exCode: 'NotFound' }
} else {
return { data: 'Contents of file' }
}
}
function main() {
const { data, exCode } = readFile('./example.txt')
if (exCode === 'NotFound') {
console.log('Could not find the file.')
return
} else if (exCode) {
// We don't know how to handle this exCode, so throw an error
throw new Error(`Unhandled exception when reading file: ${exCode}`)
}
console.log(`Contents of file: ${data}`)
}
main()
其中一些解决方案感觉工作量很大。只是抛出一个对象文字很诱人,例如throw { code: 'NotFound' }
。 不要这样做!堆栈跟踪信息附加到错误对象。如果这些对象文字中的一个曾经漏掉并成为未捕获的异常,您将无法通过堆栈跟踪来了解它发生的位置或方式。一般来说,调试会困难得多。
当您的包开始处理大量异常时,我建议使用如上所述的“返回异常”方法,以帮助您跟踪哪些异常可能来自何处(至少在您的包内部使用它 -你仍然可以为你的包用户扔东西)。有时,即使是这种解决方案也不够好。我整理了一些显式异常包来帮助处理这些情况(可以在 here 中找到。还有一个轻量版本,您可以将其复制粘贴到您的项目 here 中)。这个想法是要求用户明确列出他们希望函数调用提供哪些异常。这使得跟踪异常路径变得非常容易。
try {
// readFile() will give an exception.
// In unwrap(), you list which exceptions you except, to help with self-documentation.
// runtime checks help ensure no other kinds of exceptions slip through.
return unwrap(readFile('./example.txt'), ['NotFound'])
} catch (err) {
// Handle the exception here
}
完整示例:
// You must have the explicit-exceptions package for this code to run
const { Exception, wrap, unwrap } = require('explicit-exceptions')
const readFile = wrap(path => {
throw new Exception('NotFound')
})
function main () {
try {
return unwrap(readFile('./example.txt'), ['NotFound'])
} catch (ex) {
if (!(ex instanceof Exception)) throw ex // Not an exception, don't handle it
console.assert(ex.code === 'NotFound')
console.log('File not found')
}
}
main()
答案 6 :(得分:-3)
s