As a designer I have been trying to dig this stuff. Server side JS seems like a huge win for all kinds of small websites and interesting ui experiments, because one can stay in one language and avoid code duplication.

Yet in trying to set up some experiments that use a server-side git integration, I bumped into the kind of code described in this thread, and I find it super difficult to understand the async way of doing things.

Here’s an example from the homepage of nodegit, which seem to be among the best maintained libraries that wrap libgit2. Thus I imagine it represents idiomatic node.js What the code does, is console.log details of all the repositories commits, git log style.

// Load in the module.
var git = require('nodegit'),
async = require('async');

// Open the repository in the current directory.
git.repo('.git', function(error, repository) {
if (error) throw error;

// Use the master branch (a branch is the HEAD commit)
repository.branch('master', function(error, branch) {
if (error) throw error;

// History returns an event, and begins walking the history
var history = branch.history();

// History emits 'commit' event for each commit in the branch's history
history.on('commit', function(error, commit) {
// Print out `git log` emulation.
async.series([
function(callback) {
commit.sha(callback);
},
function(callback) {
commit.date(callback);
},
function(callback) {
commit.author(function(error, author) {
author.name(callback);
});
},
function(callback) {
commit.author(function(error, author) {
author.email(callback);
});
},
function(callback) {
commit.message(callback);
}
], function printCommit(error, results) {
if (error) throw error;
console.log('SHA ' + results[0]);
console.log(results[1] * 1000);
console.log(results[2] + ' <' + results[3] + '>');
console.log(results[4]);
});
});
});
});

It looks so alien to me! Instead of the tree-walking and looping constructs I know from synchronous languages, we deal with a history that returns events as it walks the tree (btw, why is it that we can launch the history before we attach the event?). Then we have to actually import the ‘async’ module, because, uhm, we want to specify an order by which the different parts of the message gets logged.

How then the actual callbacks work, I’d be happy if someone can explain that to me—why do I pass a function to an attribute of the object? Why don‘t I just return the value?

Because the code is not written in a lineair way, I have to keep looking back and forth between callbacks to get a mental picture of what it does.

For the record, what this translates to as synchronous Python:

from pygit2 import Repository, GIT_SORT_TOPOLOGICAL
repo = Repository('.git')

for commit in repo.walk(repo.head.target, GIT_SORT_TOPOLOGICAL):
print 'SHA %s' % commit.hex
print commit.commit_time * 1000
print '%s <%s>' % (commit.author.name, commit.author.email)
print commit.message

I imagine that, as some of the commenters note, I will be able to start reading the async style if I get enough exposure to it. I wonder though, if it does not make the barrier to entry for server-side JavaScript too high for non-full-time programmers.

In that sense it is interesting that the Meteor team chose to use the package Fibers, that allows one to write node.js in a procedural style. I imagine something like that is necessary for server side JS to become really mainstream in web design…