No.js tratamento de exceções de melhores práticas

Comecei a testar o nó.js há alguns dias. Eu percebi que o nó é terminado sempre que eu tenho uma exceção livre no meu programa. Isto é diferente do container normal do servidor que eu fui exposto onde somente o Thread do Trabalhador morre quando ocorrem exceções não tratadas e o container ainda seria capaz de receber o pedido. Isto levanta algumas questões:
  • é {[[0]} a única maneira eficaz de se proteger contra isso?
  • irá process.on('uncaughtException') capturar o exceção não tratada durante a execução de processos assíncronos também?
  • existe um módulo que já está construído (como enviar e-mail ou escrever para um arquivo) que eu poderia alavancar em caso de exceções não anotadas?

gostaria de qualquer artigo que me mostrasse as melhores práticas comuns para lidar com excepções no nó.js

Author: Rakesh Sankar, 2011-09-05

10 answers

Actualização: o Joyent agora tem o seu próprio guiamencionado em esta resposta. A informação que se segue é mais um resumo:

Erros de "atirar" com segurança

Idealmente, gostaríamos de evitar erros de desclassificação tanto quanto possível, como tal, em vez de literalmente lançar o erro, Podemos em vez disso "lançar" o erro com segurança usando um dos seguintes métodos, dependendo da nossa arquitectura de código:

  • Para código síncrono, se ocorrer um erro, devolve o erro:

    // 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)
    }
    
  • Para call-based (ie. código assíncrono), o primeiro argumento do callback é err, se um erro acontece err é o erro, se um erro não acontece então err é null. Quaisquer outros argumentos seguem o argumento 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)
        }
    })
    
  • Para eventful code, onde o erro pode acontecer em qualquer lugar, em vez de atirar o erro, dispare o error evento em alternativa:

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

Em segurança erros de "captura"

Às vezes, porém, ainda pode haver um código que lança um erro em algum lugar que pode levar a uma exceção não declarada e um potencial acidente de nossa aplicação se não o pegarmos com segurança. Dependendo de nossa arquitetura de código, podemos usar um dos seguintes métodos para pegá-lo:
  • Quando sabemos onde o erro está a ocorrer, podemos envolver essa secção num nó .domínio 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
    })
    
  • Se soubermos onde está o erro ocorrendo é código síncrono, e por qualquer razão não pode usar domínios( talvez a versão antiga do node), podemos usar a declaração de tentativa de captura:
    // 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)
    }
    

    No entanto, tenha cuidado para não usar try...catch em código assíncrono, como um erro assíncrono lançado não será pego:

    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
    }
    

    Se quiser trabalhar com try..catch em conjunto com o código assíncrono, ao executar o nó 7.4 ou superior pode usar async/await nativamente para escrever as suas funções assíncronas.

    Outra coisa a ser cuidado com try...catch é o risco de embrulhar a sua chamada de conclusão dentro da declaração try Assim:
    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
    }
    
    Isto é muito fácil de fazer à medida que o teu código se torna mais complexo. Como tal, é melhor usar os domínios ou retornar erros para evitar (1) exceções descaídas em código assíncrono (2) a tentativa de captura execução que você não quer que ele. Em linguagens que permitem uma rosca adequada em vez do estilo assíncrono de JavaScript, este é menos de problema.
  • Finalmente, no caso em que um erro não detectado acontece num lugar que não foi embrulhado num domínio ou numa declaração de captura tentar, podemos fazer a nossa aplicação não falhar usando o uncaughtException ouvinte (no entanto, fazê - lo pode colocar a aplicação num estado desconhecido ):

    // 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
    
 656
Author: balupton, 2018-09-29 13:13:39

A seguir está uma síntese e Curação de muitas fontes diferentes sobre este tópico, incluindo exemplo de código e citações de posts selecionados do blog. A lista completa das melhores práticas pode ser encontrada aqui


Melhores práticas do Node.Tratamento de erros do JS


Número 1: Usar As promessas para o tratamento de erros async

TL; DR: lidar com erros de async no estilo de callback é provavelmente o caminho mais rápido para o inferno (ou seja, a pirâmide de condenar). O melhor presente que pode dar ao seu código é usar, em vez disso, uma biblioteca de promessas respeitável, que fornece uma sintaxe de código muito compacta e familiar, como o try-catch

Caso Contrário: Nó.Js callback style, function (err, response), is a promising way to un-maintainable code due to the mix of error handling with casual code, excessive niding and awkward coding patterns

Exemplo de Código-bom

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

Exemplo de código anti-padrão-estilo de callback tratamento de erros

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

Citação do Blog:"temos um problema com promessas" (A partir do blog pouchdb, Ranqueado 11 para as palavras-chave "Node Promises")

"...E, na verdade, os callbacks fazem algo ainda mais sinistro: privam-nos da pilha, que é algo que normalmente tomamos como garantido nas linguagens de programação. Escrever código sem uma pilha é muito como dirigir um carro sem pedal de travão: você não percebe o quanto você precisa dele, até que você chegar para ele e não está lá. O objectivo das promessas é devolver - nos os fundamentos da linguagem que perdemos quando fomos async: voltar, atirar, e a pilha. Mas você tem que saber como usar as promessas corretamente, a fim de tirar proveito delas."

Número 2: Utilize apenas o objecto de erro incorporado

TL; DR: é bastante comum ver o código que lança erros como texto ou como um tipo personalizado-isto complica a lógica de manipulação de erros e a interoperabilidade entre módulos. Se rejeitar uma promessa, abra uma excepção ou envie um nó de utilização de erros.Js built-in Error object aumenta a uniformidade e evita a perda da informação de erro

Caso contrário: ao executar algum módulo, sendo incerto qual o tipo de erros que vêm em troca – torna muito mais difícil raciocinar sobre a próxima excepção e lidar com ela. Mesmo o valor, usando tipos personalizados para descrever erros pode levar à perda de informações críticas de erro como a pilha trace!

Exemplo de código-fazê-lo bem

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

Exemplo de código anti-padrão

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

Citação do Blog:"uma string não é um erro" (From the blog devthought, ranked 6 for the keywords "Node.Js error object")

"...passar uma cadeia de caracteres em vez de um erro resulta numa interoperabilidade reduzida entre módulos. Ele quebra contratos com APIs que podem estar realizando instânciasde verificação de erros, ou que querem saber mais sobre o erro. Objetos de erro, como veremos, têm propriedades muito interessantes em motores JavaScript modernos além de manter a mensagem passada para o construtor.."


Número 3: distinguir os erros operacionais dos programadores

Os erros de operações TL; DR: (por exemplo, a API recebeu uma entrada inválida) referem-se a casos conhecidos em que o impacto do erro é totalmente compreendido e pode ser tratado com ponderação. Por outro lado, erro de programador (por exemplo, tentar ler variável indefinida) refere-se a falhas de código desconhecidas que ditam para reiniciar graciosamente a aplicação

Caso contrário: poderá sempre reiniciar a aplicação quando aparecer um erro, mas porquê deixar cair ~5000 utilizadores online por causa de um erro menor e previsto (erro operacional)? o oposto também não é ideal – manter a aplicação para cima quando o problema desconhecido (erro programador) ocorreu pode levar comportamento imprevisível. Diferenciar os dois permite agir com tacto e aplicar uma abordagem equilibrada baseada no contexto em questão

Exemplo de código-fazê-lo bem

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

Exemplo de código-marcação de um erro como Operacional (aprovada)

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

Citação do Blog: "caso contrário, você arrisca o estado" (A partir do blog debugable, ranked 3 para o nó palavras-chave".Excepção não declarada")

"...pela própria natureza de como o throw funciona em JavaScript, quase nunca há nenhuma maneira segura de " pegar onde você deixado de fora", sem vazar referências, ou criando algum outro tipo de Estado quebradiço indefinido. A maneira mais segura de responder a um erro lançado é desligar o processo . Claro que, em um servidor web normal, você pode ter muitas conexões abertas, e não é razoável fechar abruptamente aqueles para baixo porque um erro foi desencadeado por outra pessoa. A melhor abordagem é enviar uma resposta de erro ao pedido que desencadeou o erro, deixando os outros terminar em seu tempo normal, e pare de ouvir novos pedidos nesse trabalhador " [[13]}


Número 4: lidar com erros centralmente, através mas não dentro do middleware

TL; DR: a lógica de manipulação de erros, como o correio para administração e registo, deve ser encapsulada num objecto dedicado e centralizado que todos os pontos finais (por exemplo, middleware expresso, trabalhos de cron, testes unitários) chamam quando um erro aparece.

Caso contrário: {[17] } não lidar com erros num único local levará à duplicação de códigos e provavelmente a erros que são tratados indevidamente

Exemplo de código - um fluxo de erro típico

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

Citação do Blog: "às vezes níveis mais baixos não podem fazer nada de útil, exceto propagar o erro para o seu chamador" (A partir do blog Joyent, Ranqueado 1 para o nó palavras-chave".Js error handling")

" ... você pode acabar lidando com o mesmo erro em vários níveis da pilha. Isso acontece quando os níveis mais baixos não podem fazer nada útil, exceto propagar o erro para o seu convocador, que faz recair o erro sobre o convocador, e assim por diante. Muitas vezes, apenas o ouvinte de alto nível sabe qual é a resposta apropriada, seja para repetir a operação, relatar um erro ao usuário, ou algo mais. Mas isso não significa que você deve tentar relatar todos os erros para um único callback de nível superior, porque esse callback em si não pode saber em que contexto o erro ocorreu "


Número 5: erros da API do documento usando Swagger

Deixe os seus chamadores de API saberem que erros podem vir em troca para que possam lidar com isto sem cair. Isto é normalmente feito com os quadros de documentação da API REST, como o Swagger

Caso contrário: um cliente da API pode decidir interromper e reiniciar apenas porque recebeu de volta um erro que não conseguia entender. Nota: o chamador da sua API pode ser você (muito típico em um ambiente microservices)

Blog citação: "Você tem que dizer aos seus chamadores que erros podem acontecer" (A partir do blog Joyent, Ranqueado 1 para o nó palavras-chave".Registo JS")

[[10]} ... nós falamos sobre como lidar com erros, mas quando você está escrevendo uma nova função, como você entrega erros para o código que chamou a sua função? ... Se você não sabe que erros podem acontecer ou não sabe o que eles significam, então seu programa não pode ser correto, exceto por acidente. Por isso, se estás a escrever uma nova função, tens de dizer ao teu chamadores que erros podem acontecer e o que eles mea

Número 6: encerre o processo graciosamente quando um estranho chegar à cidade

TL; DR: quando ocorre um erro desconhecido (um erro do programador, veja o número de melhores práticas #3)- existe incerteza sobre a saúde da aplicação. Uma prática comum sugere reiniciar o processo cuidadosamente usando uma ferramenta 'reiniciador' como Forever e PM2

Caso contrário: o objeto pode estar em um estado defeituoso (por exemplo, um emissor de eventos que é usado globalmente e não disparar mais eventos devido a alguma falha interna) e todos os pedidos futuros podem falhar ou se comportar loucamente

Exemplo de código-decidir se deseja estoirar

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

Citação no Blog: "Há três escolas de pensamentos sobre o tratamento de erros" (Do blog jsrecipes)

Há principalmente três escolas de pensamentos sobre o tratamento de erros: 1. Deixe a aplicação crash e reinicie. 2. Lidar com todos os erros possíveis e nunca cair. 3. Abordagem equilibrada entre os dois

Número 7: Usar um logger maduro para aumentar a visibilidade dos erros

TL; DR: um conjunto de ferramentas maduras de registo como Winston, Bunyan ou Log4J, irá acelerar a descoberta e compreensão de erros. Esquece a consola.log.

Caso contrário:registos ou manualmente através de um ficheiro de texto confuso sem questionar ferramentas ou um visualizador de registos decente podem mantê-lo ocupado no trabalho até tarde

Exemplo de código-logger Winston em acção

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

Citação do Blog: "permite identificar alguns requisitos (para um logger):" (Do blog strongblog)

[[10]} ... vamos identificar alguns requisitos (para um logger): 1. Marca o tempo de cada linha de Registo. Este é muito auto explicativo-você deve ser capaz de dizer quando cada entrada de log ocorreu. 2. O formato de registo deve ser fácil digerível por humanos, bem como por máquinas. 3. Permite múltiplos fluxos de destino configuráveis. Por exemplo, você pode estar escrevendo registros de rastreamento para um arquivo, mas quando um erro é encontrado, escreva para o mesmo arquivo, em seguida, para o arquivo de erro e envie um e-mail ao mesmo tempo ...

Número 8: descubra erros e tempo de inactividade usando os produtos APM

TL; DR: monitorização e produtos de desempenho (T. c. p.APM) avaliam proactivamente a sua base de código ou API para que possam auto-magicamente realçar erros, falhas e partes lentas que lhe faltavam

Caso contrário: Você pode gastar um grande esforço em medir o desempenho da API e tempo de inatividade, provavelmente você nunca estará ciente quais são as suas partes de código mais lentas no cenário do mundo real e como isso afeta o UX

Citação no Blog: "segmentos de produtos APM" (Do blog Yoni Goldberg)

[[10]}"...OS produtos APM constituem 3 segmentos principais: 1. Monitorização do sítio Web ou da API - serviços externos que monitorizam constantemente o tempo de funcionamento e o desempenho através de solicitações HTTP. Pode ser configurado em poucos minutos. A seguir estão alguns candidatos selecionados: Pingdom, robô Uptime, e Nova Relíquia 2. Instrumentação de código - família de produtos que requerem a incorporação de um agente dentro da aplicação para beneficiar apresentam detecção lenta de código, exceções estatísticas, monitoramento de desempenho e muito mais. A seguir estão alguns candidatos selecionados: Nova Relíquia, dinâmica de aplicativos 3. Operacional painel de inteligência - estas linhas de produtos estão focadas em facilitar a equipe de operações com métricas e conteúdo curativo que ajuda a ficar facilmente em cima do desempenho da aplicação. Isto geralmente envolve a agregação de várias fontes de informação (logs de Aplicação, Logs DB, log de servidores, etc) e trabalho de design do painel de bordo inicial. A seguir estão alguns candidatos seleccionados: Datadog, Splunk"

o acima é uma versão abreviada - veja aqui mais melhor práticas e exemplos

 62
Author: Yonatan, 2016-04-18 20:21:04
Pode apanhar excepções, mas é de uso limitado. Veja http://debuggable.com/posts/node-js-dealing-with-uncaught-exceptions:4c933d54-1428-443c-928d-4e1ecbdd56cb

monit, forever ou upstart pode ser usado para reiniciar o processo do nó quando ele estoura. Um encerramento gracioso é o melhor que você pode esperar (por exemplo, salvar todos os dados na memória em uncaught exception handler).

 27
Author: nponeccop, 2011-09-10 22:13:56

Domínios Nodejs é a forma mais atualizada de lidar com erros em nodejs. Domínios podem capturar tanto erros/outros eventos, bem como objetos jogados tradicionalmente. Domains also provide functionality for handling callbacks with an error passed as the first argument via the intercept method.

Tal como acontece com o tratamento normal de erros de tentativa/estilo de captura, é normalmente melhor lançar erros quando ocorrem, e bloquear áreas onde você quer isolar os erros de afectar o resto do codigo. A maneira de "bloquear" essas áreas são chamar domínio.executar com uma função como um bloco de código isolado.

Em código síncrono, o acima é suficiente-quando um erro acontece, você ou deixa que ele seja jogado, ou você pegá-lo e manuseá-lo lá, revertendo quaisquer dados que você precisa para reverter.

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

Quando o erro ocorre num callback assíncrono, você ou precisa ser capaz de lidar completamente com o rollback dos dados (estado compartilhado, dados externos como bases de dados, etc). Ou você tem para definir algo para indicar que uma exceção aconteceu - onde sempre que você se importa com essa bandeira, você tem que esperar que o callback para completar.

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
  }

})});
Um pouco desse código acima é feio, mas você pode criar padrões para si mesmo para torná-lo mais bonito, por exemplo:
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
});

actualizar (2013-09):

Acima, eu uso um futuro que implica fibras semânticas , que permitem que você espere em futuros em linha. Isso realmente permite que você use o tradicional try-catch bloqueios para tudo o que acho ser a melhor maneira de morrer. No entanto, você não pode sempre fazer isso (ou seja, no navegador)...

Também existem futuros que não requerem semântica de fibras (que então trabalham com JavaScript de navegação normal). Estes podem ser chamados futuros, promessas, ou deferreds (eu vou apenas referir-se a futuros a partir de agora). Plain-old-JavaScript futures libraries allow errors to be propagated between futures. Apenas algumas dessas bibliotecas permitem que qualquer futuro jogado seja manipulado correctamente, por isso cuidado.

Um exemplo:

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()
Isto imita uma captura normal, mesmo que as peças sejam assíncronas. Iria imprimir:
1
2
handler

Note que ele não imprime '3' porque uma exceção foi lançada que interrompe esse fluxo.

Olha para as promessas do bluebird. Note que não encontrei muitas outras bibliotecas para além destas que manipulam correctamente. excepcao. jQuery adiou, por exemplo, não-o encarregado" falho "nunca teria a exceção jogado um "então" handler, o que, na minha opinião, é um quebra de acordo.
 15
Author: B T, 2015-07-02 22:36:36
Eu escrevi sobre isso recentemente em http://snmaynard.com/2012/12/21/node-error-handling/. uma nova funcionalidade do node na versão 0.8 é domínios e permite-lhe combinar todas as formas de tratamento de erros num formulário de gestão mais fácil. Pode ler sobre eles no meu post.

Você também pode usar algo como Bugsnag para rastrear as suas excepções e ser notificado por e-mail, sala de chat ou ter um bilhete criado para uma excepção não declarada (eu sou o co-fundador da Bugsnag).

 11
Author: Simon Maynard, 2013-01-10 00:16:11

Uma instância em que a utilização de uma captura experimental pode ser apropriada é quando se utiliza um laço forEach. É síncrono, mas ao mesmo tempo você não pode apenas usar uma declaração de retorno no escopo interno. Em vez disso, uma abordagem de tentativa e captura pode ser usada para retornar um objeto de erro no escopo apropriado. Considere:

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

É uma combinação das abordagens descritas por @balupton acima.

 4
Author: Michael Yagudaev, 2012-09-11 14:26:39

Gostaria apenas de acrescentar esse passo .a biblioteca js ajuda - o a lidar com as excepções, passando-a sempre para a função do próximo passo. Portanto, você pode ter como último passo uma função que verifica por quaisquer erros em qualquer um dos passos anteriores. Esta abordagem pode simplificar muito o seu tratamento de erros.

Abaixo está uma citação da página github:

Todas as exceções lançadas são apanhadas e passadas como primeiro argumento para a próxima função. Desde que não andes de volta ao ninho funções incorporadas suas principais funções isso impede que lá nunca ser qualquer uncaught excepcao. Isto é muito importante para um nó de longa execução.Servidores JS uma vez que uma única exceção pode derrubar todo o servidor.

Além disso, pode usar o Step para controlar a execução de programas para ter uma secção de limpeza como último passo. Por exemplo, se você quiser escrever um script de compilação no nó e relatar quanto tempo levou para escrever, o último passo pode fazer isso (em vez de tentar cavar out the last callback).

 3
Author: Michael Yagudaev, 2012-06-12 17:47:14

Depois de ler este post há algum tempo, estava a pensar se seria seguro usar domínios para o tratamento de excepções a um nível de api / função. Eu queria usá-los para simplificar o código de manuseio de exceção em cada função async que eu escrevi. A minha preocupação era que usar um novo domínio para cada função introduziria sobrecarga significativa. O meu trabalho de casa parece indicar que há uma sobrecarga mínima e que o desempenho é realmente melhor com domínios do que com tentar a captura em alguns situacao.

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

 2
Author: Sudsy, 2013-09-10 04:15:57

Se quiser usar serviços no Ubuntu (Upstart): nó como um serviço no Ubuntu 11.04 com upstart, monit e para sempre.js

 1
Author: Cap, 2013-03-19 13:22:53

Os erros de captura foram muito bem discutidos aqui, mas vale a pena lembrar-se de registrar os erros em algum lugar para que você possa vê-los e corrigir as coisas.

O Bunyan é uma estrutura de Registo popular para o NodeJS-it supportst escrevendo para um monte de locais de saída diferentes, o que o torna útil para depuração local, desde que evite consola.log. ​ No controlador de erros do seu domínio, você pode cuspir o erro para um arquivo de Registo.

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

Isto pode ser demorado se tiver muitos erros e / ou servidores para verificar, para que possa valer a pena olhar para uma ferramenta como Raygun (disclaimer, eu trabalho na Raygun) para agrupar erros - ou usá-los ambos juntos. ​ Se você decidiu usar o Raygun como uma ferramenta, é muito fácil de configurar também

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

​ Crossed with using a tool like PM2 or forever, your app should be able to crash, log out what happened and reboot without any major issues.

 1
Author: K. Craven, 2015-09-29 19:51:58