Node.js Streams Inherit Error-Handling Behavior From EventEmitter
I started digging into Node.js recently as a means to understand why my Gulp.js build script wasn't working. This lead me down a rabbit hole of exploration into Streams in Node.js and, more specifically, into how streams handle errors. And, while this may be obvious to most Node.js developers, it took me a good while to figure out: Streams don't really do any error handling; they inherit error handling behavior from EventEmitter.
Ok, that last statement isn't entirely true - Node.js Streams do handle some errors around .pipe() and around how connections get cleaned up; but, they don't suppress errors. This means that an error emitted by a Stream will turn into an exception unless there is at least one externally-bound "error" event handler. This last caveat is really the point of this blog post.
Other than looking in the code, the evidence of this can be seen in the stack trace of uncaught exceptions. First, let's look at emitting an error in an instance of EventEmitter:
var events = require( "events" );
var badEventer = new events.EventEmitter();
badEventer.emit( "error", new Error( "Something went wrong." ) );
When we run this EventEmitter code, we get the following terminal output:
events.js:72
throw er; // Unhandled 'error' event
As you can see, the emitted event is being thrown() in the events.js module, line 72.
Ok, now let's look at emitting an error event in an instance of Readable stream:
var stream = require( "stream" );
var badStream = new stream.Readable();
badStream.emit( "error", new Error( "Something went wrong." ) );
When we run this Readable steam code, we get the following terminal output:
events.js:72
throw er; // Unhandled 'error' event
As you can see, it's the same exact error. This is because Node.js Streams are EventEmitters in that they [Streams] have the EventEmitter class in their prototype chain and use the EventEmitter as a super constructor.
Ok, so I know this blog post is super basic and you probably think this is like Node.js 101; but, building a solid mental model of Node.js streams has been a really challenging (yet awesome) adventure for me. I still haven't debugged my Gulp.js problem; but, I think I'm getting really close to understanding what is going wrong.
Want to use code from this post? Check out the license.
Reader Comments