Since moving to San Francisco, I've realized that despite its attractive market for start-up investments, Beijing is something of a tech backwater outside of a few companies. Not only are people here using a lot of technologies such as Ruby on Rails that are almost unused in China, but they're also crazy about a quite a few things I'd never even heard of while working at a fairly hip mobile start-up in Beijing. Top on that list was Node.js, so I worked through the free Node Beginner Book and then took Code School's course on it. Their interactive system is great for learning, but I still find the need to have some review notes to help it sink in. Here goes:

Level 1

Curl is useful! Why didn't I think of that? After setting up your Hello World server with this in your server.js:

var http = require("http");

http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}).listen(8080);

There's no need to bother firing up a browser. You can verify the server's running with curl!

curl http://localhost:8080

Level 2

You can add a second listener for requests if you want to:

server = http.createServer(function (request, response) {
  // do stuff
}).listen(8080);

server.on('request', function(request, response){
  // 2nd listener
});

Since http.Server is an event emitter and http.createServer takes a requestListener as a parameter and requestListeners are functions that automatically listens to 'request' events, these two are identical:

http.createServer(function(request, response){ ... });
// is the same as
var server = http.createServer();
server.on('request', function(request, response){ ... });

The second syntax above is how we usually add our own event listeners in node.

Level 3

Read streams and write streams are event emitters. Request is a read stream; response is a write stream. You can make them do stuff with

somestring.on('someevent', function(data){...});

File Copying

var fs = require('fs');

var file = fs.createReadStream("somefile");
var newfile = fs.createWriteStream("somefile_copy");
// Pipe handles read/write speed mismatches for you
file.pipe(newFile); 

Handling back pressure manually if you don't use pipe

Unfortunately, there's the risk that the stream that's writing data out can't keep up with data that you're reading in. If memory fills up and more data keeps streaming in, bad things happen.

We can check to see if a writeStream's buffer is full with var bufferokay = writeStream.write(chunk);. If that returns false, you can shut down the readStream with readStream.pause(). Then once its buffer is empty writeStream will automatically send a 'drain' event. By listening for it and using a callback to readStream.resume() we can make sure the stream starts reading again once we're ready.

var fs = require('fs');

var file = fs.createReadStream("HUGEFILE.avi");
var newFile = fs.createWriteStream("HUGEFILE_copy.avi");

file.on('data', function(chunk) {
  var bufferokay = newFile.write(chunk);
  if (!bufferokay) { file.pause()}
  newFile.write(chunk);
});

newFile.on('drain', function(){
  file.resume();
})

file.on('end', function() {
  newFile.end();
});

Leave a Reply

Your email address will not be published. Required fields are marked *