Quelle est la bonne façon de gérer les erreurs avec les flux? Je sais déjà qu'il y a un événement «d'erreur» sur lequel vous pouvez écouter, mais je veux en savoir plus sur des situations arbitrairement compliquées.
Pour commencer, que faites-vous lorsque vous voulez faire une simple chaîne de tuyaux:
input.pipe(transformA).pipe(transformB).pipe(transformC)...
Et comment créer correctement l'une de ces transformations pour que les erreurs soient gérées correctement?
Plus de questions connexes:
- lorsqu'une erreur se produit, qu'arrive-t-il à l'événement «fin»? Ne se fait-il jamais virer? Est-il parfois viré? Cela dépend-il de la transformation / du flux? Quelles sont les normes ici?
- existe-t-il des mécanismes pour propager les erreurs à travers les tuyaux?
- les domaines résolvent-ils efficacement ce problème? Les exemples seraient bien.
- les erreurs qui proviennent d'événements «d'erreur» ont-elles des traces de pile? Quelquefois? Jamais? y a-t-il un moyen d'en obtenir un?
Promise
les frameworks le rendent beaucoup plus simpleRéponses:
transformer
Les flux de transformation sont à la fois lisibles et inscriptibles, et sont donc de très bons flux «intermédiaires». Pour cette raison, ils sont parfois appelés
through
flux. Ils sont similaires à un flux duplex de cette manière, sauf qu'ils fournissent une interface agréable pour manipuler les données plutôt que de simplement les envoyer. Le but d'un flux de transformation est de manipuler les données lorsqu'elles sont acheminées dans le flux. Vous voudrez peut-être faire des appels asynchrones, par exemple, ou dériver quelques champs, remapper certaines choses, etc.Pour savoir comment créer un flux de transformation, voir ici et ici . Tout ce que tu dois faire est :
_transform
méthode qui prend un(chunk, encoding, callback)
.Le morceau est vos données. La plupart du temps, vous n'aurez pas à vous soucier de l'encodage si vous travaillez
objectMode = true
. Le rappel est appelé lorsque vous avez terminé de traiter le bloc. Ce bloc est ensuite poussé vers le flux suivant.Si vous voulez un bon module d'aide qui vous permettra de faire du stream très facilement, je suggère through2 .
Pour la gestion des erreurs, continuez à lire.
tuyau
Dans une chaîne de tubes, la gestion des erreurs n'est en effet pas triviale. Selon ce fil, .pipe () n'est pas conçu pour transmettre les erreurs. Donc quelque chose comme ...
... n'écouterait que les erreurs sur le flux
c
. Si un événement d'erreur était émisa
, cela ne serait pas transmis et, en fait, serait déclenché. Pour faire cela correctement:Maintenant, bien que la deuxième méthode soit plus verbeuse, vous pouvez au moins conserver le contexte dans lequel vos erreurs se produisent. C'est généralement une bonne chose.
Une bibliothèque que je trouve utile si vous avez un cas où vous souhaitez uniquement capturer les erreurs à la destination et que vous ne vous souciez pas tellement de l'endroit où cela s'est produit est le flux d'événements .
fin
Lorsqu'un événement d'erreur est déclenché, l'événement de fin ne sera pas déclenché (explicitement). L'émission d'un événement d'erreur mettra fin au flux.
domaines
D'après mon expérience, les domaines fonctionnent très bien la plupart du temps. Si vous avez un événement d'erreur non géré (c'est-à-dire émettant une erreur sur un flux sans écouteur), le serveur peut planter. Maintenant, comme le souligne l'article ci-dessus, vous pouvez envelopper le flux dans un domaine qui devrait correctement détecter toutes les erreurs.
La beauté des domaines est qu'ils conserveront les traces de la pile. Bien que le flux d'événements fasse également un bon travail dans ce domaine.
Pour plus d'informations, consultez le manuel du flux . Assez en profondeur, mais super utile et donne d'excellents liens vers de nombreux modules utiles.
la source
.on('error')
gestionnaire dans une fonction anonyme, c'esta.on('error', function(e){handleError(e)})
-à- dire que vous pouvez simplement êtrea.on('error', handleError)
Si vous utilisez node> = v10.0.0, vous pouvez utiliser stream.pipeline et stream.finished .
Par exemple:
Voir ce PR github pour plus de discussion.
la source
finished
cependant, quand apipeline
déjà un rappel?les domaines sont obsolètes. vous n'en avez pas besoin.
pour cette question, les distinctions entre transform ou inscriptible ne sont pas si importantes.
La réponse de mshell_lauren est excellente, mais comme alternative, vous pouvez également écouter explicitement l'événement d'erreur sur chaque flux que vous pensez être une erreur. et réutilisez la fonction de gestionnaire si vous préférez.
cela empêche la tristement célèbre exception non interceptée si l'un de ces flux déclenche son événement d'erreur
la source
error
, on peut aussi bien alors se contenter du fait que chaque événement est distinct; 2) Quelles bibliothèques de streaming sont écrites ci-dessus, à part la fonctionnalité native de Node.js? et 3) pourquoi est-ce important de savoir comment ils gèrent les événements en interne, alors que cela permet évidemment à quiconque d'attacher des gestionnaires d'erreurs supplémentaires en plus de tout ce qui existe déjà?Les erreurs de toute la chaîne peuvent être propagées vers le flux le plus à droite à l'aide d'une simple fonction:
qui peut être utilisé comme:
la source
.on("error", handler)
ne prend en charge que les erreurs de flux, mais si vous utilisez des flux de transformation personnalisés,.on("error", handler)
ne détectez pas les erreurs qui se produisent dans la_transform
fonction. On peut donc faire quelque chose comme ça pour contrôler le flux des applications: -this
Le mot-clé en_transform
fonction se réfère àStream
lui-même, qui est unEventEmitter
. Vous pouvez donc utilisertry catch
comme ci-dessous pour détecter les erreurs et les transmettre plus tard aux gestionnaires d'événements personnalisés.De cette façon, vous pouvez séparer votre logique et vos gestionnaires d'erreurs. En outre, vous pouvez choisir de ne gérer que certaines erreurs et d'en ignorer d'autres.
UPDATE
Alternative: RXJS Observable
la source
Utilisez le package multipipe pour combiner plusieurs flux en un seul flux duplex. Et gérez les erreurs en un seul endroit.
la source
Utilisez le modèle Node.js en créant une mécanique de flux de transformation et en appelant son rappel
done
avec un argument afin de propager l'erreur:la source
Try catch ne capturera pas les erreurs qui se sont produites dans le flux, car elles sont levées après que le code appelant soit déjà fermé. vous pouvez vous référer à la documentation:
https://nodejs.org/dist/latest-v10.x/docs/api/errors.html
la source