Node.js最佳实践异常处理

mom*_*omo 736 exception-handling serverside-javascript node.js

我几天前刚开始尝试node.js.我已经意识到只要我的程序中有未处理的异常,Node就会终止.这与我所暴露的普通服务器容器不同,只有当未处理的异常发生且容器仍然能够接收请求时,工作线程才会死亡.这引出了一些问题:

  • process.on('uncaughtException')防范它的唯一有效方法吗?
  • process.on('uncaughtException')在异步进程执行期间是否会捕获未处理的异常?
  • 是否有一个已经构建的模块(例如发送电子邮件或写入文件),在未捕获的异常情况下我可以利用它?

我将非常感谢任何指针/文章,它将向我展示在node.js中处理未捕获的异常的常见最佳实践

bal*_*ton 718

更新: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)
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 对于基于回调的(即异步)代码,回调的第一个参数是err,如果发生错误err则是错误,如果没有发生错误则errnull.任何其他参数都遵循以下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)
        }
    })
    
    Run Code Online (Sandbox Code Playgroud)
  • 对于事件代码,错误可能发生在任何地方,而不是抛出错误,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)
    
    Run Code Online (Sandbox Code Playgroud)

安全地"捕捉"错误

但有时候,如果我们没有安全地捕获它,可能仍然会有代码在某处抛出错误,这可能导致未捕获的异常和我们的应用程序可能崩溃.根据我们的代码架构,我们可以使用以下方法之一来捕获它:

  • 当我们知道错误发生的位置时,我们可以将该部分包装在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
    })
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果我们知道错误发生在哪里是同步代码,并且由于某种原因无法使用域(可能是旧版本的节点),我们可以使用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)
    }
    
    Run Code Online (Sandbox Code Playgroud)

    但是,请注意不要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
    }
    
    Run Code Online (Sandbox Code Playgroud)

    如果您确实希望try..catch与异步代码一起使用,那么在运行Node 7.4或更高版本时,您可以使用async/await本机编写异步函数.

    另外需要注意的try...catch是将完成回调包装在try语句中的风险如下:

    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
    }
    
    Run Code Online (Sandbox Code Playgroud)

    随着代码变得更加复杂,这个问题很容易实现.因此,最好使用域或返回错误以避免(1)异步代码中未被捕获的异常(2)try catch捕获执行您不希望它.在允许正确线程而不是JavaScript的异步事件 - 机器风格的语言中,这不是一个问题.

  • 最后,如果在未包含在域或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
    
    Run Code Online (Sandbox Code Playgroud)

  • 现在[域名被io.js弃用](https://iojs.org/api/domain.html):"**此模块正在等待弃用.**一旦替换API完成,此模块将完全已弃用...绝对必须具有域提供的功能的用户可能暂时依赖它,但应该期望将来必须迁移到其他解决方案." (21认同)
  • 谢谢Raynos,更新.你有一个解释'try catch`罪恶的来源吗?因为我喜欢用证据支持这一点.还修复了同步示例. (5认同)
  • @balupton应该抛出错误以进行错误处理.绝对不应该避免它们.没有任何关于他们打破应用程序或其他任何东西的执行.Java和大多数其他现代语言都支持异常.在阅读了一些被监禁的帖子之后,我唯一的结论就是人们对它们的了解并不是很好,因此害怕它们.害怕不确定的怀疑.至少在20年前,这场辩论最终决定支持例外. (5认同)
  • [域api现在已被弃用](https://nodejs.org/api/domain.html)?他们提到了一个替代API - 任何人都知道什么时候会出现,它会是什么样子? (5认同)
  • 更新了域和事件.欢迎反馈. (4认同)
  • 这个答案不再有效.域解决了这个问题(由node.js推荐) (2认同)
  • 这在它写成之前已经过时了十年。返回值不适用于错误。这个答案没有告诉您如何在异步发生错误时正确隔离代码。此外,这提倡可怕地使用 uncaughtException 处理程序,它只会让您的程序继续处于不良状态。这个答案应该有负面影响。 (2认同)
  • 将"err"作为第一个参数传递给Node.js库中的回调的唯一原因是因为它是异步调用.您提出的建议是回归编程社区如何处理大约1993年的错误:错误返回代码. (2认同)
  • 谢谢 Timothy,也许值得一提的是 io.js 对 depreaction 的定义以及“稳定性:0 - 已弃用。已知此功能有问题,已计划进行更改。不要依赖它。使用该功能可能会导致警告。向后兼容性不应该被期待。” - 奇怪的是他们已经弃用了它而没有任何东西可以替代它。这可能是延续您**不**需要**域名的理想,但如果您确实需要它们,它们就存在,即使它们有问题。 (2认同)

Yon*_*tan 87

以下是关于此主题的许多不同来源的摘要和管理,包括代码示例和所选博客帖子的引用.可以在此处找到完整的最佳实践列表


Node.JS错误处理的最佳实践


Number1:使用promises进行异步错误处理

TL; DR:处理回调样式中的异步错误可能是地狱的最快方式(也就是厄运的金字塔).您可以为代码提供的最好礼物是使用信誉良好的promise库,它提供了非常紧凑和熟悉的代码语法,如try-catch

否则: Node.JS回调样式,函数(错误,响应),由于错误处理与临时代码,过度嵌套和笨拙的编码模式的混合,是一种有前途的无法维护代码的方法

代码示例 - 很好

doWork()
.then(doWork)
.then(doError)
.then(doWork)
.catch(errorHandler)
.then(verify);
Run Code Online (Sandbox Code Playgroud)

代码示例反模式 - 回调样式错误处理

getData(someParameter, function(err, result){
    if(err != null)
      //do something like calling the given callback function and pass the error
    getMoreData(a, function(err, result){
          if(err != null)
            //do something like calling the given callback function and pass the error
        getMoreData(b, function(c){ 
                getMoreData(d, function(e){ 
                    ...
                });
            });
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

博客引用:"我们的承诺存在问题" (来自博客pouchdb,关键字"Node Promises"排名第11位)

"......事实上,回调做的事情更加险恶:它们剥夺了我们的堆栈,这是我们在编程语言中通常认为理所当然的事情.编写没有堆栈的代码就像驾驶没有制动踏板的汽车一样:你没有意识到你需要它有多么糟糕,直到你达到它并且它不存在.承诺的全部意义是让我们回到我们去异步时失去的语言基础:返回,抛出和堆栈.但是你必须知道如何正确使用承诺才能利用它们. "


Number2:仅使用内置的Error对象

TL; DR:看到以字符串或自定义类型引发错误的代码非常常见 - 这使错误处理逻辑和模块之间的互操作性变得复杂.无论是拒绝承诺,抛出异常还是发出错误 - 使用Node.JS内置的Error对象可以增加一致性并防止丢失错误信息

否则:当执行某个模块时,不确定哪种类型的错误会得到回报 - 这使得更难以推理即将到来的异常并处理它.甚至值得,使用自定义类型来描述错误可能会导致丢失关键错误信息,如堆栈跟踪!

代码示例 - 做得对

    //throwing an Error from typical function, whether sync or async
 if(!productToAdd)
 throw new Error("How can I add new product when no value provided?");

//'throwing' an Error from EventEmitter
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));

//'throwing' an Error from a Promise
 return new promise(function (resolve, reject) {
 DAL.getProduct(productToAdd.id).then((existingProduct) =>{
 if(existingProduct != null)
 return reject(new Error("Why fooling us and trying to add an existing product?"));
Run Code Online (Sandbox Code Playgroud)

代码示例反模式

//throwing a String lacks any stack trace information and other important properties
if(!productToAdd)
    throw ("How can I add new product when no value provided?");
Run Code Online (Sandbox Code Playgroud)

博客引用:"字符串不是错误" (来自博客devthought,关键字"Node.JS错误对象"排名第6)

"...传递字符串而不是错误会导致模块之间的互操作性降低.它会破坏与可能正在执行错误检查实例的API的合同,或者想要了解错误的更多信息.正如我们所看到的,错误对象非常有用现代JavaScript引擎中有趣的属性除了将消息传递给构造函数之外."


Number3:区分操作与程序员错误

TL; DR:操作错误(例如,API收到无效输入)是指已完全理解错误影响并且可以仔细处理的已知情况.另一方面,程序员错误(例如,尝试读取未定义的变量)是指未指定的代码失败,需要优雅地重新启动应用程序

否则:当出现错误时,您可能总是重新启动应用程序,但是为什么让~5000个在线用户因为轻微的预测错误而失败(操作错误)?相反的情况也不理想 - 当发生未知问题(程序员错误)时保持应用程序可能导致不可预测的行为.区分这两者允许巧妙地采取行动并基于给定的背景应用平衡的方法

代码示例 - 做得对

    //throwing an Error from typical function, whether sync or async
 if(!productToAdd)
 throw new Error("How can I add new product when no value provided?");

//'throwing' an Error from EventEmitter
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));

//'throwing' an Error from a Promise
 return new promise(function (resolve, reject) {
 DAL.getProduct(productToAdd.id).then((existingProduct) =>{
 if(existingProduct != null)
 return reject(new Error("Why fooling us and trying to add an existing product?"));
Run Code Online (Sandbox Code Playgroud)

代码示例 - 将错误标记为可操作(可信)

//marking an error object as operational 
var myError = new Error("How can I add new product when no value provided?");
myError.isOperational = true;

//or if you're using some centralized error factory (see other examples at the bullet "Use only the built-in Error object")
function appError(commonType, description, isOperational) {
    Error.call(this);
    Error.captureStackTrace(this);
    this.commonType = commonType;
    this.description = description;
    this.isOperational = isOperational;
};

throw new appError(errorManagement.commonErrors.InvalidInput, "Describe here what happened", true);

//error handling code within middleware
process.on('uncaughtException', function(error) {
    if(!error.isOperational)
        process.exit(1);
});
Run Code Online (Sandbox Code Playgroud)

博客引用:"否则你冒着风险"(来自博客可调试,关键字"Node.JS未捕获异常"排名第3)

" ...就如何在JavaScript中使用throw的本质而言,几乎从来没有任何方法可以安全地"拾取你离开的地方",不会泄漏引用,或者创建其他类型的未定义的脆弱状态.最安全的响应方式抛出错误就是关闭进程.当然,在普通的Web服务器中,你可能打开了很多连接,因为错误是由其他人触发而突然关闭它们是不合理的.更好的方法是向触发错误的请求发送错误响应,同时让其他人在正常时间内完成,并停止侦听该工作中的新请求"


Number4:集中处理错误,但不是在中间件中处理错误

TL; DR:错误处理逻辑,例如邮件管理和日志记录应该封装在一个专用的集中式对象中,当出现错误时,所有端点(如Express中间件,cron作业,单元测试)都会调用.

否则:不在一个地方处理错误将导致代码重复,并可能导致错误处理错误

代码示例 - 典型的错误流程

//DAL layer, we don't handle errors here
DB.addDocument(newCustomer, (error, result) => {
    if (error)
        throw new Error("Great error explanation comes here", other useful parameters)
});

//API route code, we catch both sync and async errors and forward to the middleware
try {
    customerService.addNew(req.body).then(function (result) {
        res.status(200).json(result);
    }).catch((error) => {
        next(error)
    });
}
catch (error) {
    next(error);
}

//Error handling middleware, we delegate the handling to the centrzlied error handler
app.use(function (err, req, res, next) {
    errorHandler.handleError(err).then((isOperationalError) => {
        if (!isOperationalError)
            next(err);
    });
});
Run Code Online (Sandbox Code Playgroud)

博客引用: "有时较低级别除了将错误传播给其调用者之外无法做任何有用的事情"(来自博客Joyent,关键字"Node.JS错误处理"排名第1)

"...你最终可能会在堆栈的几个级别处理相同的错误.当较低级别无法执行任何有用的操作时会发生这种情况,除非将错误传播给调用者,后者会将错误传播给调用者,等等.通常情况下,只有顶级调用者知道适当的响应是什么,是重试操作,向用户报告错误还是别的.但这并不意味着你应该尝试将所有错误报告给单个顶级回调,因为该回调本身无法知道错误发生在什么上下文中"


Number5:使用Swagger的文档API错误

TL; DR:让你的API调用者知道哪些错误可能会得到回报,这样他们就可以周到地处理这些错误而不会崩溃.这通常使用像Swagger这样的REST API文档框架来完成

否则: API客户端可能决定崩溃并重新启动,因为他收到了一个他无法理解的错误.注意:API的调用者可能是您(在微服务环境中非常典型)

博客引用: "你必须告诉你的来电者会发生什么错误"(来自博客Joyent,关键字"Node.JS logging"排名第一)

...我们已经讨论过如何处理错误,但是当您编写新函数时,如何将错误传递给调用函数的代码?...如果您不知道可能发生的错误或不知道它们的含义,那么您的程序除非意外,否则无法正确执行.因此,如果您正在编写新功能,则必须告诉您的呼叫者可能发生的错误以及它们的用途


Number6:当一个陌生人来到城镇时,优雅地关闭这个过程

TL; DR:当发生未知错误(开发人员错误,请参阅最佳实践编号#3)时 - 应用程序健康状况存在不确定性.通常的做法是建议使用Forever和PM2等"重启"工具重新启动流程

否则:当捕获到一个不熟悉的异常时,某些对象可能处于故障状态(例如,全局使用的事件发射器,并且由于某些内部故障而不再触发事件)并且所有将来的请求可能会失败或表现得很疯狂

代码示例 - 决定是否崩溃

//deciding whether to crash when an uncaught exception arrives
//Assuming developers mark known operational errors with error.isOperational=true, read best practice #3
process.on('uncaughtException', function(error) {
 errorManagement.handler.handleError(error);
 if(!errorManagement.handler.isTrustedError(error))
 process.exit(1)
});


//centralized error handler encapsulates error-handling related logic 
function errorHandler(){
 this.handleError = function (error) {
 return logger.logError(err).then(sendMailToAdminIfCritical).then(saveInOpsQueueIfCritical).then(determineIfOperationalError);
 }

 this.isTrustedError = function(error)
 {
 return error.isOperational;
 }
Run Code Online (Sandbox Code Playgroud)

博客引用: "关于错误处理有三种思路"(来自博客jsrecipes)

...错误处理主要有三种思路:1.让应用程序崩溃并重新启动它.2.处理所有可能的错误,永不崩溃.3.两者之间的平衡接近


Number7:使用成熟的记录器来增加错误可见性

TL; DR:一组成熟的日志工具,如Winston,Bunyan或Log4J,将加速错误发现和理解.所以忘记console.log.

否则:浏览console.logs或手动浏览凌乱的文本文件而不查询工具或体面的日志查看器可能会让你忙着工作直到很晚

代码示例 - Winston记录器正在运行

//your centralized logger object
var logger = new winston.Logger({
 level: 'info',
 transports: [
 new (winston.transports.Console)(),
 new (winston.transports.File)({ filename: 'somefile.log' })
 ]
 });

//custom code somewhere using the logger
logger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });
Run Code Online (Sandbox Code Playgroud)

博客引用: "让我们确定一些要求(对于记录器):"(来自博客strongblog)

...让我们确定一些要求(对于记录器):1.每个日志行的时间戳.这个是非常自我解释的 - 你应该能够告诉每个日志条目何时发生.2.记录格式应易于被人类和机器消化.3.允许多个可配置的目标流.例如,您可能正在将跟踪日志写入一个文件,但遇到错误时,请写入同一文件,然后写入错误文件并同时发送电子邮件...


Number8:使用APM产品发现错误和停机时间

TL; DR:监控和性能产品(也称为APM)主动测量您的代码库或API,以便他们可以自动神奇地突出您丢失的错误,崩溃和慢速部件

否则:您可能会花费大量精力来测量API性能和停机时间,可能您永远不会意识到哪些是您在真实场景下最慢的代码部分以及它们如何影响UX

博客引用: "APM产品细分"(来自博客Yoni Goldberg)

"... APM产品构成3个主要部分:1.网站或API监控 -通过HTTP请求持续监控正常运行时间和性能的外部服务.可以在几分钟内完成设置.以下几个选定的竞争者:Pingdom,Uptime Robot和New Relic 2代码检测 -产品系列需要在应用程序中嵌入代理,以便利用慢速代码检测,异常统计,性能监控等功能.以下几个选定的竞争者:New Relic,App Dynamics 3.运营智能仪表板 -这些行产品的重点是为运营团队提供指标和策划内容,以帮助轻松掌握应用程序性能.这通常涉及聚合多个信息源(应用程序日志,数据库日志,服务器日志等)和前期仪表板设计以下几个选定的竞争者:Datadog,Splunk"


以上是缩短版本 - 请参阅此处更多最佳做法和示例

  • 为了透明起见,请注意 http://goldbergyoni.com 是 @Yonatan 自己的网站。 (2认同)

npo*_*cop 29

您可以捕获未捕获的异常,但它的用途有限.见http://debuggable.com/posts/node-js-dealing-with-uncaught-exceptions:4c933d54-1428-443c-928d-4e1ecbdd56cb

monit,forever或者upstart可以用于在崩溃时重启节点进程.您可以期望正常关闭(例如,在未捕获的异常处理程序中保存所有内存数据).

  • +1链接很有用,谢谢.我仍然在node.js的上下文中寻找最佳实践和"优雅重启"的含义 (4认同)

B T*_*B T 13

nodejs域是处理nodejs中的错误的最新方法.域可以捕获错误/其他事件以及传统抛出的对象.域还提供处理回调的功能,并通过拦截方法将错误作为第一个参数传递.

与正常的try/catch样式错误处理一样,通常最好在错误发生时抛出错误,并阻止您希望隔离错误的区域影响其余代码."阻止"这些区域的方法是使用函数作为隔离代码块来调用domain.run.

在同步代码中,上面就足够了 - 当一个错误发生时你或者让它被抛出,或者你抓住并处理它,恢复你需要恢复的任何数据.

try {  
  //something
} catch(e) {
  // handle data reversion
  // probably log too
}
Run Code Online (Sandbox Code Playgroud)

当异步回调中发生错误时,您需要能够完全处理数据回滚(共享状态,数据库等外部数据).或者你必须设置一些东西来表明发生了异常 - 你关心那个标志,你必须等待回调完成.

var err = null;
var d = require('domain').create();
d.on('error', function(e) {
  err = e;
  // any additional error handling
}
d.run(function() { Fiber(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(err != null) {
    // handle data reversion
    // probably log too
  }

})});
Run Code Online (Sandbox Code Playgroud)

上面的一些代码是丑陋的,但你可以为自己创建模式,使其更漂亮,例如:

var specialDomain = specialDomain(function() {
  // do stuff
  var future = somethingAsynchronous();
  // more stuff

  future.wait(); // here we care about the error
  if(specialDomain.error()) {
    // handle data reversion
    // probably log too
  } 
}, function() { // "catch"
  // any additional error handling
});
Run Code Online (Sandbox Code Playgroud)

更新(2013-09):

上面,我使用了一个暗示纤维语义的未来,它允许你在线上等待期货.这实际上允许您使用传统的try-catch块来实现一切 - 我觉得这是最好的方法.但是,你不能总是这样做(即在浏览器中)......

还有一些期货不需要光纤语义(然后可以使用普通的浏览JavaScript).这些可以称为期货,承诺或延期(我将从这里引用期货).普通的JavaScript期货库允许在期货之间传播错误.只有其中一些库允许正确处理任何抛出的未来,所以要小心.

一个例子:

returnsAFuture().then(function() {
  console.log('1')
  return doSomething() // also returns a future

}).then(function() {
  console.log('2')
  throw Error("oops an error was thrown")

}).then(function() {
  console.log('3')

}).catch(function(exception) {
  console.log('handler')
  // handle the exception
}).done()
Run Code Online (Sandbox Code Playgroud)

这模仿了正常的try-catch,即使这些部分是异步的.它会打印:

1
2
handler
Run Code Online (Sandbox Code Playgroud)

请注意,它不会打印'3',因为抛出了一个中断流动的异常.

看看蓝鸟的承诺:

请注意,我没有找到除这些之外的许多其他库来正确处理抛出的异常.例如,jQuery延迟了 - "失败"处理程序永远不会抛出一个'then'处理程序的异常,在我看来这是一个交易破坏者.

  • [域名api现在似乎已被弃用...](https://nodejs.org/api/domain.html) (19认同)

小智 11

我最近在http://snmaynard.com/2012/12/21/node-error-handling/上写了这篇文章.版本0.8中的节点的新功能是域,允许您将所有形式的错误处理组合到一个更简单的管理表单中.你可以在我的帖子中阅读它们.

你也可以使用像Bugsnag这样的东西来跟踪未被捕获的异常并通过电子邮件,聊天室通知或者为未捕获的异常创建一张票(我是Bugsnag的联合创始人).

  • 域模块现已正式弃用。https://nodejs.org/api/domain.html (2认同)