Working with Events and Strings in Node.js

Being new to Node.js, it took me an amazing amount of time to figure out how to assgin event stream chunks (foo.on('data', ...)) to a variable and work with it. An amazing amount of time, because it's actually really easy if you understand callbacks (which I didn't) and because all the examples I could find worked with console.log. In this case, I didn't want to log the result, but pass it, process it, etc. So here's an example from GitMD with some additional comments to help you along the way.

The goal here is to take a path, make an http.get request, grab the response stream and pass it back.

Simple enough? Well initially, thinking like a functional (non-async) developer, I wanted to return the response as a string, all sync-like.

The issue I was having was scope. I was initalizing the return string (mdown) inside of the event handler (res.on('data', ...)) and trying to return it. That doesn't work.

Instead, I have to build the data string as it's chunked back via the data event. Once complete (identified by the end event), I can pass it to the callback.

Note: I've simpilified this example, modifing and removing code which doesn't relate to this topic, specifically event handling and string. See: github.com/jmervine/node-gitmd/blog/master/gitmd.js for the complete example.

function fetch (path, callback) {
    /***
     * First, create your return string holder. This must be
     * initialized as an empty string, or your result string
     * will start with 'undefined'.
     ***/
    var mdown = '';
    http.get(this.gitpath(path), function (res) {
       /***
        * Listen for 'data', when you find it add the resulting
        * chunk of data to your return string (mdown).
        ***/
       res.on('data', function (chunk) {
           mdown += chunk;
       });
       /***
        * Listen for 'error', you'll want to handle them.
        * Convention says that the first argument passed to a
        * callback should be errors, so I'm doing that here.
        ***/
       res.on('error', function (error) {
           callback(error, null);
       });
       /***
        * Listen for 'end', that's what tells you that things
        * have finished up and it's time to do something with
        * the return string you've collected. Convention says
        * that if there's no errors, pass null in it's place
        * (the first argument).
        ***/
       return res.on('end', function () {
           callback(null, mdown);
       });
    }).on('error', function (error) {
       /***
        * In this example, I'm also listening for 'http' errors
        * just to be safe.
        ***/
       callback(error, null);
    });
}

For a more complex example (passing custom events and responding), see functional_app.js, which passes an custom event message to the parent that forks it, functional.js. Also in the same example project as the above example — GitMD.

See the following for detailed documentation:

Published on in Node.js