When writing node applications, there are a few concepts that are important to understand in order to create large-scale applications. I’m going to cover a few concepts that I think are important when building non-trivial sites with node.js. If you have suggestions of other important topics or concepts, or areas you are struggling with, let me know and I’ll try to cover them as well.
It’s asynchronous, duh
If you’ve done anything or read anything with node.js, I’m sure you are aware that it is built on an event-driven, asynchronous model. It’s one of the first things you have to come to grips with if you are building anything substantial. Because node.js applications are single threaded, it’s very important that you keep to the asynchronous model. When you do, your apps will be amazingly fast and responsive. If you don’t, you’re application will slow to a crawl. Let’s take the simplest web server example:
This code is running on a single thread, waiting for a web request. When a web request, comes in you want to pass the work off to an asynchronous callback handler, freeing the main thread to respond to more requests. If you block the main event loop, then no more requests will processed until it completes.
It can take a while to get used to this model, especially coming from a blocking or multi-threaded paradigm, which uses a different approach for concurrency. The first time I ran into this was building the Austin code camp site. To save the results from the form, I abstracted the work into a separate function. on the request handler, I called the save function, then returned the response.
But I forgot that the work to save the data, was done asynchronously, so my output log looked like this:
calling save returning response saving the data
Because the work to save the data was done asynchronously, I sent the response was sent before the data was actually saved. (Keep in mind, this is not always a bad thing, like saving a log statement, but not waiting to see if it completes or not.) What I needed to do was use a continuation model, and pass in a callback that completes the html request, when the request to save the data completes, or sends back an error.
It can take a while to get used to the continuation model, and it can get really messy when you need to complete several operations before completing a request. There are a lot of workflow modules that you can use to make this easier. It’s also relatively simple to build your own. In fact it’s practically a rite of passage that a lot of node developers do. It’s also possible to abstract this by using EventEmitters, which we’ll discuss in a later topic.