首页 文章

Node.js最佳实践异常处理

提问于
浏览
675

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

  • process.on('uncaughtException') 是防范它的唯一有效方法吗?

  • 在执行异步进程期间 process.on('uncaughtException') 会捕获未处理的异常吗?

  • 是否有一个已经构建的模块(例如发送电子邮件或写入文件),在未捕获的异常情况下我可以利用它?

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

10 回答

  • 662

    更新:Joyent现在在this answer中提到their own guide . 以下信息更多的是摘要:

    安全地“抛出”错误

    理想情况下,我们希望尽可能避免未被捕获的错误,因此,我们可以使用以下方法之一安全地“抛出”错误,而不是根据我们的代码架构:

    • 对于同步代码,如果发生错误,则返回错误:
    // 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 是错误,如果没有发生错误则 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)
        }
    })
    
    // 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 domain
    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 本地编写异步函数 .

    使用 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
    }
    

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

    • 最后,如果在未包含在域或try catch语句中的地方发生未被捕获的错误,我们可以通过使用 uncaughtException 侦听器使我们的应用程序不崩溃(但是这样做可以将应用程序放入unknown state):
    // 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
    
  • 15

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


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


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

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

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

    Code example - good

    doWork()
    .then(doWork)
    .then(doError)
    .then(doWork)
    .catch(errorHandler)
    .then(verify);
    

    code example anti pattern – callback style error handling

    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){ 
                        ...
                    });
                });
            });
        });
    });
    

    Blog quote: "We have a problem with promises" (来自博客pouchdb,关键字"Node Promises"排名第11位)

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


    Number2:仅使用内置的Error对象

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

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

    Code example - doing it right

    //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?"));
    

    code example anti pattern

    //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?");
    

    Blog quote: "A string is not an error" (来自博客devthought,关键字“Node.JS错误对象”排名第6)

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


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

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

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

    Code example - doing it right

    //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?"));
    

    code example - marking an error as operational (trusted)

    //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);
    });
    

    Blog Quote :"Otherwise you risk the state"(来自博客可调试,关键字"Node.JS uncaught exception"排名3)

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


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

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

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

    Code example - a typical error flow

    //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);
        });
    });
    

    Blog quote: "Sometimes lower levels can’t do anything useful except propagate the error to their caller"(来自博客Joyent,关键字“Node.JS错误处理”排名第1)

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


    Number5:使用Swagger记录API错误

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

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

    Blog quote: "You have to tell your callers what errors can happen"(来自博客Joyent,关键字“Node.JS logging”排名第1)

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


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

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

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

    Code example - deciding whether to crash

    //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;
     }
    

    Blog quote: "There are three schools of thoughts on error handling"(来自博客jsrecipes)

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


    Number7:使用成熟的 Logger 来增加错误可见性

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

    Otherwise: 浏览console.logs或手动浏览凌乱的文本文件而无需查询工具或体面的日志查看器可能会让您忙碌工作直到很晚

    Code example - Winston logger in action

    //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' });
    

    Blog quote: "Lets identify a few requirements (for a logger):"(来自博客strongblog)

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


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

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

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

    Blog quote: "APM products segments"(来自博客Yoni Goldberg)

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


    The above is a shortened version - see here more best practices and examples

  • 4

    这里已经很好地讨论了捕获错误,但是值得记住将错误记录到某处,以便您可以查看它们并修复内容 .

    Bunyan是NodeJS的流行日志框架 - 它支持写入一堆不同的输出位置,这使得它对本地调试很有用,只要你避免使用console.log . 在您的域的错误处理程序中,您可以将错误吐出到日志文件中 .

    var log = bunyan.createLogger({
      name: 'myapp',
      streams: [
        {
          level: 'error',
          path: '/var/tmp/myapp-error.log'  // log ERROR to this file
        }
      ]
    });
    

    如果您有大量的错误和/或服务器需要检查,这可能会耗费时间,因此可能值得研究像Raygun(免责声明,我在Raygun工作)这样的工具将错误组合在一起 - 或者将它们一起使用 . 如果你决定使用Raygun作为工具,它也很容易设置

    var raygunClient = new raygun.Client().init({ apiKey: 'your API key' });
    raygunClient.send(theError);
    

    使用像PM2这样的工具或永远使用,您的应用程序应该能够崩溃,注销发生的事情并重启而不会出现任何重大问题 .

  • 3

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

    您还可以使用类似Bugsnag的内容来跟踪未捕获的异常,并通过电子邮件,聊天室通知或为未捕获的异常创建故障单(我是Bugsnag的联合创始人) .

  • 1

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

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

  • 2

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

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

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

    try {  
      //something
    } catch(e) {
      // handle data reversion
      // probably log too
    }
    

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

    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
      }
    
    })});
    

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

    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
    });
    

    UPDATE (2013-09):

    上面,我使用了一个暗示fibers semantics的未来,它允许你在线上等待期货 . 这实际上允许您使用传统的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()
    

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

    1
    2
    handler
    

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

    看看蓝鸟承诺:

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

  • 11

    我想补充一点,Step.js library总是将它传递给下一步功能,帮助你处理异常 . 因此,您可以使用一个函数来检查上述任何步骤中的任何错误 . 这种方法可以大大简化您的错误处理 .

    以下是github页面的引用:

    捕获的任何异常都被捕获并作为第一个参数传递给下一个函数 . 只要你没有嵌套回调函数内联你的主要功能,这就防止了任何未捕获的异常 . 这对于长时间运行的node.JS服务器非常重要,因为单个未捕获的异常可能会导致整个服务器崩溃 .

    此外,您可以使用Step来控制脚本的执行,以便将清理部分作为最后一步 . 例如,如果您想在Node中编写构建脚本并报告编写所花费的时间,那么最后一步可以做到(而不是试图挖出最后一个回调) .

  • 66

    使用try-catch的一个实例可能是使用forEach循环时 . 它是同步的,但同时你不能只在内部范围内使用return语句 . 相反,可以使用try和catch方法在适当的范围内返回Error对象 . 考虑:

    function processArray() {
        try { 
           [1, 2, 3].forEach(function() { throw new Error('exception'); }); 
        } catch (e) { 
           return e; 
        }
    }
    

    它是上面@balupton描述的方法的组合 .

  • 1

    在前一段时间阅读这篇文章后,我想知道在api /功能级别上使用域进行异常处理是否安全 . 我想用它们来简化我写的每个异步函数中的异常处理代码 . 我担心的是,为每个函数使用一个新域会带来很大的开销 . 我的作业似乎表明,开销很小,而且在某些情况下,域名的性能实际上比使用try catch更好 .

    http://www.lighthouselogic.com/#/using-a-new-domain-for-each-async-function-in-node/

  • 27

    如果你想在Ubuntu(Upstart)中使用服务:Node as a service in Ubuntu 11.04 with upstart, monit and forever.js

相关问题