几天前我刚刚开始尝试 Node.js。我意识到每当我的程序中出现未处理的异常时,节点就会终止。这与我接触过的普通服务器容器不同,在普通服务器容器中,当发生未处理的异常时,只有工作线程会终止,并且容器仍然能够接收请求。这提出了几个问题:
- Is
process.on('uncaughtException')
唯一有效的防范方法是什么?
- Will
process.on('uncaughtException')
在异步进程执行期间也捕获未处理的异常?
- 是否有一个已经构建的模块(例如发送电子邮件或写入文件),我可以在未捕获异常的情况下利用它?
我将不胜感激任何能够向我展示处理 node.js 中未捕获异常的常见最佳实践的指针/文章
更新:Joyent 现在有他们自己的指南。以下信息更多的是摘要:
安全地“抛出”错误
理想情况下,我们希望尽可能避免未捕获的错误,因此,我们可以根据我们的代码架构,使用以下方法之一安全地“抛出”错误,而不是字面上抛出错误:
-
对于同步代码,如果发生错误,则返回错误:
// Define divider as a syncrhonous function
var divideSync = function(x,y) {
// if error condition?
if ( y === 0 ) {
// "throw" the error safely by returning it
return new Error("Can't divide by zero")
}
else {
// no error occured, continue on
return x/y
}
}
// Divide 4/2
var result = divideSync(4,2)
// did an error occur?
if ( result instanceof Error ) {
// handle the error safely
console.log('4/2=err', result)
}
else {
// no error occured, continue on
console.log('4/2='+result)
}
// Divide 4/0
result = divideSync(4,0)
// did an error occur?
if ( result instanceof Error ) {
// handle the error safely
console.log('4/0=err', result)
}
else {
// no error occured, continue on
console.log('4/0='+result)
}
-
对于基于回调(即异步)的代码,回调的第一个参数是err
,如果发生错误err
是错误,如果错误没有发生那么err
is null
。任何其他参数都遵循err
争论:
var divide = function(x,y,next) {
// if error condition?
if ( y === 0 ) {
// "throw" the error safely by calling the completion callback
// with the first argument being the error
next(new Error("Can't divide by zero"))
}
else {
// no error occured, continue on
next(null, x/y)
}
}
divide(4,2,function(err,result){
// did an error occur?
if ( err ) {
// handle the error safely
console.log('4/2=err', err)
}
else {
// no error occured, continue on
console.log('4/2='+result)
}
})
divide(4,0,function(err,result){
// did an error occur?
if ( err ) {
// handle the error safely
console.log('4/0=err', err)
}
else {
// no error occured, continue on
console.log('4/0='+result)
}
})
-
For eventful代码,其中错误可能发生在任何地方,而不是抛出错误,而是触发error事件代替:
// Definite our Divider Event Emitter
var events = require('events')
var Divider = function(){
events.EventEmitter.call(this)
}
require('util').inherits(Divider, events.EventEmitter)
// Add the divide function
Divider.prototype.divide = function(x,y){
// if error condition?
if ( y === 0 ) {
// "throw" the error safely by emitting it
var err = new Error("Can't divide by zero")
this.emit('error', err)
}
else {
// no error occured, continue on
this.emit('divided', x, y, x/y)
}
// Chain
return this;
}
// Create our divider and listen for errors
var divider = new Divider()
divider.on('error', function(err){
// handle the error safely
console.log(err)
})
divider.on('divided', function(x,y,result){
console.log(x+'/'+y+'='+result)
})
// Divide
divider.divide(4,2).divide(4,0)
安全地“捕获”错误
但有时,仍然可能有代码在某个地方抛出错误,如果我们不安全地捕获它,这可能会导致未捕获的异常和应用程序的潜在崩溃。根据我们的代码架构,我们可以使用以下方法之一来捕获它:
-
当我们知道错误发生在哪里时,我们可以将该部分包装在Node.js 域
var d = require('domain').create()
d.on('error', function(err){
// handle the error safely
console.log(err)
})
// catch the uncaught errors in this asynchronous or synchronous code block
d.run(function(){
// the asynchronous or synchronous code that we want to catch thrown errors on
var err = new Error('example')
throw err
})
-
如果我们知道错误发生在同步代码的位置,并且由于某种原因无法使用域(可能是旧版本的节点),我们可以使用 try catch 语句:
// catch the uncaught errors in this synchronous code block
// try catch statements only work on synchronous code
try {
// the synchronous code that we want to catch thrown errors on
var err = new Error('example')
throw err
} catch (err) {
// handle the error safely
console.log(err)
}
不过,请注意不要使用try...catch
在异步代码中,异步抛出的错误不会被捕获:
try {
setTimeout(function(){
var err = new Error('example')
throw err
}, 1000)
}
catch (err) {
// Example error won't be caught here... crashing our app
// hence the need for domains
}
如果您确实想与try..catch
与异步代码结合使用,当运行 Node 7.4 或更高版本时,您可以使用async/await
原生地编写异步函数。
Another thing to be careful about with `try...catch` is the risk of wrapping your completion callback inside the `try` statement like so:
var divide = function(x,y,next) {
// if error condition?
if ( y === 0 ) {
// "throw" the error safely by calling the completion callback
// with the first argument being the error
next(new Error("Can't divide by zero"))
}
else {
// no error occured, continue on
next(null, x/y)
}
}
var continueElsewhere = function(err, result){
throw new Error('elsewhere has failed')
}
try {
divide(4, 2, continueElsewhere)
// ^ the execution of divide, and the execution of
// continueElsewhere will be inside the try statement
}
catch (err) {
console.log(err.stack)
// ^ will output the "unexpected" result of: elsewhere has failed
}
This gotcha is very easy to do as your code becomes more complex. As such, it is best to either use domains or to return errors to avoid (1) uncaught exceptions in asynchronous code (2) the try catch catching execution that you don't want it to. In languages that allow for proper threading instead of JavaScript's asynchronous event-machine style, this is less of an issue.
-
最后,如果未捕获的错误发生在未包含在域或 try catch 语句中的位置,我们可以使用以下方法使应用程序不会崩溃uncaughtException
侦听器(但是这样做可能会将应用程序置于未知状态):
// catch the uncaught errors that weren't wrapped in a domain or try catch statement
// do not use this in modules, but only in applications, as otherwise we could have multiple of these bound
process.on('uncaughtException', function(err) {
// handle the error safely
console.log(err)
})
// the asynchronous or synchronous code that emits the otherwise uncaught error
var err = new Error('example')
throw err
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)