Look! I used a closure!

I’m really proud of myself: I actually used a Javascript closure, like a grown up software engineer! Here’s what happened:

I’m working on a dashboard for Wired Pier, sometimes known as the Observatory Network, sometimes known as the Environment Field Station. Regardless of the museum’s inability to decide what the damn thing is called, it’s a pretty cool network: It’s a collection of instruments that measure environmental data from the atmosphere and the bay water; data loggers that pick up that data and digitize it; and a few servers that parse, store and serve that data to our exhibits as well as to the public.

Somehow, I found myself responsible for the integrity of the network. One of the first steps I took was to start building a dashboard that will help me monitor all these different nodes of the network, and use the process of building it to understand how this thing is even put together. It is a very educational process for me…

For starters, I wanted to see if all the pingable machines do, actually, ping, right? You can ping a machine from a NodeJS program using pingJS.

var ping = require('ping');
var hosts = {
  'machine1': '192.168.1.80',
  'machine2': '192.168.1.90',
  'machine3': '192.168.1.100'
};

So I thought I’d do something like this:

for (var host in hosts){
  ping.sys.probe(hosts[host], function(isAlive) {
    // I the real thing I don't print to console, 
    // but rather actually do something useful...
    console.log(host + " is " + (isAlive ? "alive" : "dead")); 
  });
} 

But what happened is that by the time the machines ping back, host had already changed, and since it takes them a while to respond, it’s the very last value that was pinged. The result looks something like this:

machine3 is alive
machine3 is dead
machine3 is alive

If I wanted to know which machine responded to the ping and which didn’t, I had to know the value of host in the ping’s callback scope.
Enter closures. At least, I think. According to MDN:

Closures […] ‘remember’ the environment in which they were created.

So I guess this qualifies:

for (var host in hosts){
  (function(h) {
    ping.sys.probe(hosts[h], function(isAlive) {
      console.log(h + " is " + (isAlive ? "alive" : "dead")); 
    });
  })(host); 
}

What happens here is that I create an anonymous function, to which I call with host as an argument. now h, living inside the function’s scope, is stuck with the value of host at the time that the function was invoked, while host itself can move on with its life.

machine1 is alive
machine2 is dead
machine3 is alive

Leave a Reply

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