Skip to main content
Antal István

The callback hell that never was

A chaotic tangle of nested brackets and chains on the left, pulled apart by a hand into a clean, ordered vertical stack of blocks on the right.

Let's talk about callbacks. People seem to get terrified by them, because they see something like this:

var mysql = require('mysql'),
    db = mysql.createClient({
        user: 'root',
        password: 'root'
    }),
    id = 1;

db.query('USE mydb', function (err) {
    //some code here
    db.query('SELECT * FROM whatever WHERE id=?', [id], function (err, foo) {
        if (foo) {
            //some other code
            db.query('UPDATE whatever SET bar=?', [foo.bar], function (err) {
                db.query('INSERT INTO someothertable (sometime) VALUES (NOW())', function () {
                    //some code
                    console.log("It's done");
                });
            });
        }
    });
    //more code
});

This has the potential to turn into hard to understand spaghetti code. But we don't have to write it like this. We don't have to inline every function; we can simply name them instead.

var mysql = require('mysql'),
    db = mysql.createClient({
        user: 'root',
        password: 'root'
    }),
    id = 1;

function init(fn) {
    db.query('USE mydb', fn);
}

function fetch(id, fn) {
    db.query('SELECT * FROM whatever WHERE id=?', [id], fn);
}

function checker(err, foo) {
    if (foo) {
        //some other code
        update(foo.bar);
    }
}

function update(bar) {
    db.query('UPDATE whatever SET bar=?', [bar], function (err) {
        db.query('INSERT INTO someothertable (sometime) VALUES (NOW())', function () {
            //some code
            console.log("It's done");
        });
    });
}

init(function () {
    fetch(id, checker);
})

We could also put this in a module or wrap a (pseudo) class around it if we wanted to. The main point is that we don't have to nest inline callbacks to get the job done; we can name them.

Related