Async callbacks are async

Async callbacks force you to learn how to deal with a single flow.


So I’ve been spending some of my free time writing things for Node.js. It’s awesome if you know javascript or, like me, decides to stop suffering and use CoffeeScript. One of the strangest moments while learning to deal with the async, mono-threaded nature of Node was a code using exec like this:

exec    = require('child_process').exec

result =
    error: null
    stdout: ''
    stderr: ''
exec 'echo testing', (error, stdout, stderr) ->
    result['error'] = error
    result['stdout'] = stdout
    result['stderr'] = stderr
console.log "'#{result['error']}' '#{result['stderr']}' '#{result['stdout']}'"

This is the js result compiled by coffee:

(function() {
  var exec, result;
  exec = require('child_process').exec;
  result = {
    error: null,
    stdout: '',
    stderr: ''
  };
  exec('echo testing', function(error, stdout, stderr) {
    result['error'] = error;
    result['stdout'] = stdout;
    return result['stderr'] = stderr;
  });
  console.log("'" + result['error'] + "' '" + result['stderr'] + "' '" + result['stdout'] + "'");
}).call(this);

It took me some minutes to understand that callback functions like the one that exec takes aren’t really executed synchronously, they are more like fire and forget, what really happens with this code is that the exec is called and the flow continues, arriving at console.log before the callback has actually finished and updated the values. I am sure that most of the js programmers are looking at me with their ‘noob’ faces but as I said, I am testing and learning as I go!

The code below illustrates it very well:

exec    = require('child_process').exec

result =
    error: null
    stdout: ''
    stderr: ''
exec 'sleep 10', (error, stdout, stderr) ->
    result['error'] = error
    result['stdout'] = stdout
    result['stderr'] = stderr
    console.log "'#{result['error']}' '#{result['stderr']}' '#{result['stdout']}'"
console.log "Out the function"

And this is the result of running this code. As you can see, the code reaches the Out of the function line and THEN finishes waiting for the callback to finish.

coredump@janie:~ $ coffee test.coffee 
Out the function
'null' '' ''
coredump@janie:~ $ 

Functions like that are common specially on browser/javascript applications and force you to think differently about program flow and how exactly to solve that. If the console.log line is moved inside the callback function body, it works, but again it may end printing on a totally different time than what you intended. There are talks and a feature request for Node to support a synchronous version of exec and relatives, but if this is going to happen it will be on version 0.7 or later.

cya!

 
comments powered by Disqus