Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with: Chris Peterson
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with: Chris Peterson@override11 )

Object Mode Streams Do Not Decode Strings Into Buffers In Node.js

By Ben Nadel on

In Node.js, when you work with Readable and Writable streams, string values are decoded into Buffers by default. You can override this by initializing a stream with "decodeStrings: false"; but, if you omit this configuration, it defaults to true. But, what happens if a stream is running in "Object Mode"? Are strings still decoded into buffers? It turns out, they are not. A string, passing through an "Object Mode" stream, remains a string.

To test this, I created a simple Readable and Writable subclass that runs in Object Mode. Then, I read one chunk from the readable stream, logged it out, and then wrote it to the writable stream:

  • // Require our code node modules.
  • var stream = require( "stream" );
  • var util = require( "util" );
  •  
  •  
  • // ----------------------------------------------------------------------------------- //
  • // ----------------------------------------------------------------------------------- //
  •  
  •  
  • // I am a simple readable stream in Object Mode that pushes the same message onto the
  • // internal buffer over and over again.
  • // --
  • // CAUTION: Do not use me in "flow" mode as I will never end - I'm the juggernaut!
  • function ReadableObjects() {
  •  
  • stream.Readable.call(
  • this,
  • {
  • objectMode: true,
  • decodeStrings: true // Attempting to force Buffers.
  • }
  • );
  •  
  • }
  •  
  • util.inherits( ReadableObjects, stream.Readable );
  •  
  • // I push the same message onto the internal buffer.
  • ReadableObjects.prototype._read = function( _sizeIsIgnoredInObjectMode ) {
  •  
  • this.push( "Shut up... Just shut up... You had me at 'hello'." );
  •  
  • }
  •  
  •  
  • // ----------------------------------------------------------------------------------- //
  • // ----------------------------------------------------------------------------------- //
  •  
  •  
  • // I am simple writable stream in Object Mode that logs-out the chunks it receives.
  • function WritableObjects() {
  •  
  • stream.Writable.call(
  • this,
  • {
  • objectMode: true,
  • decodeStrings: true // Attempting to force Buffers.
  • }
  • );
  •  
  • }
  •  
  • util.inherits( WritableObjects, stream.Writable );
  •  
  • // I log the chunk and chunk data type to the console.
  • WritableObjects.prototype._write = function( chunk, encoding, doneWriting ) {
  •  
  • console.log( "In _write:", chunk );
  • console.log( "Encoding:", encoding );
  • doneWriting();
  •  
  • };
  •  
  •  
  • // ----------------------------------------------------------------------------------- //
  • // ----------------------------------------------------------------------------------- //
  •  
  •  
  • // Create our testing stream instances (in Object Mode).
  • var readable = new ReadableObjects();
  • var writable = new WritableObjects();
  •  
  • // Since the readable stream will never end, we only want to test this on one data
  • // event in NON-FLOW mode. As such, we have to wait for a readable event and then
  • // read one chunk and explicitly pass it the writable stream.
  • readable.once(
  • "readable",
  • function handleReadable() {
  •  
  • var chunk = readable.read();
  •  
  • console.log( "In readable:", chunk );
  •  
  • // NOTE: Forcing this to a string to see if it gets decoded into a buffer.
  • writable.write( chunk.toString() );
  •  
  • }
  • );

As you can see, for good measure, I'm even including "decodeStrings: true" in an attempt to force the string decoding. But, when we run this code, we get the following terminal output:

ben$ node test.js
In readable: Shut up... Just shut up... You had me at 'hello'.
In _write: Shut up... Just shut up... You had me at 'hello'.
Encoding: utf8

As you can see, the string value remains a string value throughout the stream life cycle, when the stream is running in Objet Mode.

As a side note, if the original Readable stream had pushed a Buffer instance, instead of a String instance, then the value would have remained a Buffer throughout the stream life cycle. It's not that values are being converted to strings in Object Mode - it's that values aren't being converted at all: value in becomes value out, no transformation.




Reader Comments

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.