Qual é a maneira correta de lidar com erros com fluxos? Já sei que há um evento de 'erro' que você pode ouvir, mas quero saber mais detalhes sobre situações arbitrariamente complicadas.
Para iniciantes, o que você faz quando deseja fazer uma cadeia simples de tubos:
input.pipe(transformA).pipe(transformB).pipe(transformC)...
E como você cria adequadamente uma dessas transformações para que os erros sejam tratados corretamente?
Mais perguntas relacionadas:
- quando ocorre um erro, o que acontece com o evento 'final'? Ele nunca é demitido? Às vezes é demitido? Depende da transformação / fluxo? Quais são os padrões aqui?
- existem mecanismos para propagar erros através dos canos?
- os domínios resolvem esse problema efetivamente? Exemplos seria bom.
- erros que saem de eventos 'error' têm rastreamentos de pilha? As vezes? Nunca? existe uma maneira de obter um deles?
Promise
estruturas de torná-lo muito mais simplesRespostas:
transformar
Os fluxos de transformação são legíveis e graváveis e, portanto, são realmente bons fluxos 'médios'. Por esse motivo, às vezes são chamados de
through
fluxos. Eles são semelhantes a um fluxo duplex dessa maneira, exceto que eles fornecem uma interface agradável para manipular os dados em vez de apenas enviá-los. O objetivo de um fluxo de transformação é manipular os dados conforme eles são canalizados através do fluxo. Você pode fazer algumas chamadas assíncronas, por exemplo, ou derivar alguns campos, remapear algumas coisas, etc.Para saber como criar um fluxo de transformação, veja aqui e aqui . Tudo o que tem a fazer é :
_transform
método que leva a(chunk, encoding, callback)
.O pedaço é seus dados. Na maioria das vezes, você não precisará se preocupar com a codificação se estiver trabalhando
objectMode = true
. O retorno de chamada é chamado quando você terminar de processar o bloco. Esse pedaço é então empurrado para o próximo fluxo.Se você quer um bom módulo auxiliar que permita realizar o fluxo realmente muito facilmente, sugiro o through2 .
Para tratamento de erros, continue lendo.
tubo
Em uma cadeia de tubulação, o tratamento de erros é de fato não trivial. De acordo com este segmento, o .pipe () não foi criado para encaminhar erros. Então, algo como ...
... só ouviria erros no fluxo
c
. Se um evento de erro fosse emitidoa
, isso não seria transmitido e, de fato, seria lançado. Para fazer isso corretamente:Agora, embora a segunda maneira seja mais detalhada, você pode pelo menos manter o contexto de onde seus erros ocorrem. Isso geralmente é uma coisa boa.
Uma biblioteca que eu acho útil, se você tem um caso em que deseja capturar apenas os erros no destino e não se importa muito com o local em que isso aconteceu, é o fluxo de eventos .
fim
Quando um evento de erro é acionado, o evento final não será acionado (explicitamente). A emissão de um evento de erro encerrará o fluxo.
domínios
Na minha experiência, os domínios funcionam muito bem na maioria das vezes. Se você tiver um evento de erro não tratado (ou seja, emitindo um erro em um fluxo sem um ouvinte), o servidor poderá travar. Agora, como o artigo acima indica, você pode agrupar o fluxo em um domínio que deve capturar corretamente todos os erros.
A beleza dos domínios é que eles preservarão os rastreamentos de pilha. Embora o fluxo de eventos faça um bom trabalho nisso também.
Para ler mais, confira o manual do stream . Bastante detalhado, mas super útil e oferece ótimos links para vários módulos úteis.
fonte
.on('error')
manipulador em uma função anônima ou seja,a.on('error', function(e){handleError(e)})
pode ser apenasa.on('error', handleError)
Se você estiver usando o nó> = v10.0.0, poderá usar stream.pipeline e stream.finished .
Por exemplo:
Veja este github PR para mais discussão.
fonte
finished
quandopipeline
já tem um retorno de chamada?domínios estão obsoletos. você não precisa deles.
para esta pergunta, as distinções entre transformação ou gravável não são tão importantes.
A resposta de mshell_lauren é ótima, mas, como alternativa, você também pode ouvir explicitamente o evento de erro em cada fluxo que você acha que pode ter erro. e reutilize a função de manipulador, se preferir.
isso evita a exceção infame e não capturada, se um desses fluxos disparar seu evento de erro
fonte
error
, pode-se então aceitar o fato de que cada evento é distinto; 2) quais bibliotecas de streaming são escritas acima, exceto a funcionalidade nativa do Node.js. e 3) por que importa como eles lidam com eventos internamente, quando isso obviamente permite a qualquer pessoa anexar manipuladores de erro adicionais sobre o que já existe?Erros de toda a cadeia podem ser propagados para o fluxo mais à direita usando uma função simples:
que pode ser usado como:
fonte
.on("error", handler)
cuida apenas dos erros de fluxo, mas se você estiver usando fluxos personalizados do Transform,.on("error", handler)
não identifique os erros que ocorrem dentro da_transform
função. Portanto, é possível fazer algo assim para controlar o fluxo do aplicativo:this
A palavra-chave na_transform
função se refere aStream
si mesma, que é umEventEmitter
. Então você pode usartry catch
como abaixo para capturar os erros e depois passá-los para os manipuladores de eventos personalizados.Dessa forma, você pode manter sua lógica e manipuladores de erros separados. Além disso, você pode optar por manipular apenas alguns erros e ignorar outros.
Alternativa de atualização : RXJS observável
fonte
Use o pacote multipipe para combinar vários fluxos em um fluxo duplex. E lide com erros em um só lugar.
fonte
Use o padrão Node.js criando uma mecânica de fluxo Transform e chamando seu retorno de chamada
done
com um argumento para propagar o erro:fonte
O try catch não captura os erros que ocorreram no fluxo, porque eles são lançados após o código de chamada já ter sido encerrado. você pode consultar a documentação:
https://nodejs.org/dist/latest-v10.x/docs/api/errors.html
fonte