Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

node.js with Chalkers

In the JavaScript module where Chalkers uses node.js to create a dynamic site, he uses some pre built code that was not explained in the videos, which is ok because looking it up is good.

But I wondered if anyone could help he uses a file called profile.js and that uses something call and emitter.. some of the code is shown below.. I am finding it hard to understand how it works.

var util = require("util");

/**

  • An EventEmitter to get a Treehouse students profile.
  • @param username
  • @constructor */ function Profile(username) {

    EventEmitter.call(this);

    var profileEmitter = this;

2 Answers

What this part of the code does, is to create a class that inherits from the Node.js core module 'EventEmitter'. This way you can use all the functionality of the EventEmitter class within your own little module! Imagine the below is all in profile.js where we define our own EventEmitter. We can then import that module and listen for events we emit with Profile

var util = require("util");
var https = require("https");

function Profile(username) {
     //This line will inherit all the properties of event emitter 
     EventEmitter.call(this);

     var profileEmitter = this;

     var request = https.get("someapi/${username}.json",function(err, response) {
               var body = "";
               response.on("data",function(chunck){
                       body += chunck;
                        //now we can emit our own custom event here!!!! Due to the fact that we are inheriting from EventEmitter
                        profileEmitter.emit("dataIsComing", body);
                });

               response.on("end", function(){
                       var json =JSON.parse(body);
                       //now we can emit our own custom event here again!!!!!
                       profileEmitter.emit("endOfDataReached", json);
               })
     }     
}

//now finalize all the inheriting from EventEitter
util.inherits(Profile, EventEmitter);

module.exports = Profile;

Now imagine here we are in app.js

var Profile = require('./profile.js');

//now we instantiate our ProfileEmitter which will run all the code in our constuctor function of profile.js
var profileEmitter = new Profile('alexanderlabianca');

//now remember the custom Events we emitted? we can listen for them here and do stuff when those events occur
profileEmitter.on("dataIsComing", function(body){
             console.log(body);
});

//or even log all the data returned from the api
profileEmitter.on("endOfDataReached", function(json){
          console.log(json);
});

Again, this is only possible since we inherited from EventEmitter in Profile.js. Which gives us access to the .on() and .emit() methods.

Keep in mind that this is not doing any error handling. This is just to bring across the point. And you may see that in profile.js the response parameter looks very similar to how we use Profile in app.js. That is because the response coming back from https.get(url,callback) is inheriting from EventEmitter as well!!! I highly encourage to read more about the EventEmitter if you love Node.js as much as I do.

Can you explain what the core module EventEmitter does. I kind of mean like if we create a prototype of the string class we I think inherit from it the string.length chart() etc. What properties etc do we gain access to

I guess I just do not know and do not understand what EventEmitter is and does.

The most important methods you get access to after inheriting from EventEmitter are the .on() and .emit() method. You use the .on() method to listen for events your envent emitter is emitting. And you use the .emit() method to emit those events. Imagine you want to read from a file and want to do something special at certain points (like when the file is closed or a certain word is found etc.) during the process of reading the file. The best way to do this in node is to use an event emitter. You use the two methods in conjunction with each other. For example: If an error occurs in your event emitter function

if(error) {
    emitter.emit("error", error);
}

The .emit() method takes 2 arguments:

  1. The type of event you want to emit. Is always a string. So here you are emitting an event called 'error'
  2. The second argument is always the data you want to pass to the listening function .on()

So now you can listen anywhere for that 'error' event and process the error data

emitter.on("error",function(error) {
        console.log(error);
});

Do you see how in the callback I use the error data? That is the data I passed as a second argument in the emit function. You can emit anything you want. A full file reading event emitter could look like this:

//This is in myEmitter.js
var EventEmitter = require('EventEmitter').EventEmitter;
var fs = require('fs'); //this is just the fs node module that let's us read local files
var util = require('util');

function ReadFileEmitter() {
     EventEmitter.call(this);  //call the parent constructor
     this.files = []     //create a property 'files' which is an empty array as of right now
}

util.inherits(ReadFileEmitter, EventEmitter);

//Add a function that let's us add files to our files array
ReadFileEmitter.prototype.addFile = function(file) {
      this.files.push(file);
      return this;   //just returns itself so we can do chaining later on 
}

//Add a function to simply read all files and console.log every time we are done reading a file
ReadFileEmitter.prototype.readFiles = function() {
       var self = this;
       self.files.forEach(function(file) {
                fs.readFile(file, 'utf8', function(err, content) {
                           if(err) {
                                 return self.emit('error', err); //if there is an error when reading the file, we emit an error event
                                 //and return immediately
                           }
                           self.emit('fileread', file)  //if no error, we emit an event 'fileread' that let's us know that the file is read

                 });
       });
}

module.exports = ReadFileEmitter;

Now we can read some files

//this is in app.js
var FileReader = require('./myEmitter.js');

var fileReaderObject = new FileReader();

fileReaderObject.addFile('someFile.txt');
fileReader.readFiles();
fileReader.on('fileread', function(file) {
       console.log('File is read: ' + file);
});

fileRead.on('error', function(err) {
       console.log('Error: ' + err);
});