Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Avoiding the pyramid of doom

by Eric Bower

async-flow-control

neurosnap.net

@neurosnap

@neurosnap

What is the Pyramid of Doom?

The answer to that is that if you need more than 3 levels of indentation, you're screwed anyway, and should fix your program. Linux CodeStyle

What's the big deal?

Measuring nesting of popular Github repositories Repo

What does this "study" tell us?

The Task

Method #1: Callback Hell, NSFW Demo

var articles = [];
get(compile_url('freep.com'), function(err, freep_response) {
    if (err) throw err;
    articles = articles.concat(process_response(freep_response));
    get(compile_url('detroitnews.com'), function(err, det_response) {
        if (err) throw err;
        articles = articles.concat(process_response(det_response));
        get(compile_url('battlecreekenquirer.com'), function(err, battle_response) {
            if (err) throw err;
            articles = articles.concat(process_response(battle_response));
            get(compile_url('hometownlife.com'), function(err, hometown_response) {
                if (err) throw err;
                articles = articles.concat(process_response(hometown_response));
                console.log(articles);
            });
        });
    });
});

Method #1: Callback Hell

Method #2: Callbacks with Counter Demo

var sites = ['detroitnews.com', 'freep.com', ...];
var articles = [];
var response_counter = 0;
for (var i = 0; i < sites.length; i++) {
    var site = sites[i];
    get(compile_url(site), function(index, err, response) {
        if (err) throw err;
        articles = articles.concat(process_response(response));
        response_counter++;
        if (response_counter == sites.length) {
          console.log(articles);
        }
    }.bind(this, i));
}

Method #2: Callbacks with Counter

Method #3: Third Party Library 'async' Demo

function parallel_cb(site) {
    return function(callback) {
        get(compile_url(site), function(err, response) {
            callback(err, response);
        });
    };
}
async.parallel([
    parallel_cb('detroitnews.com'),
    parallel_cb('freep.com')
], function(err, responses) {
    if (err) throw err;
    var articles = [];
    for (var i = 0; i < responses.length; i++) {
        articles = articles.concat(process_response(responses[i]));
    }
    console.log(articles);
});

Method #3: Third Party Library 'async'

Method #4: Promises using 'bluebird' Demo

var current = Promise.resolve();
Promise.map(config.sites, function(url) {
    current = current.then(function() {
        return getAsync(compile_url(url));
    });
    return current;
}).map(function(response) {
    return process_response(response);
}).then(function(results) {
    console.log(_.flatten(results));
}).catch(function(err) {
    throw err;
});

Method #4: Promises using 'bluebird' Demo

Method #5: Coroutines using ES6 & 'bluebird' Demo

(Promise.coroutine(function* () {
  let articles = [];
  let responses;
  try {
      //responses = yield [for (site of config.sites) getAsync(compile_url(site))];
      responses = yield [
          getAsync(compile_url('detroitnews.com')),
          getAsync(compile_url('freep.com'))
      ];
  } catch (err) {
      throw err;
  }
  for (let i = 0; i < responses.length; i++) {
      articles = articles.concat(process_response(responses[i]));
  }
  console.log(articles);
}))();

Method #5: Coroutines using ES6 & 'bluebird'

Method #6: Async/Await using ES7

(async function() {
  let articles = [];
  let responses;
  try {
      //responses = await [for (site of config.sites) getAsync(compile_url(site))];
      responses = await [
          getAsync(compile_url('detroitnews.com')),
          getAsync(compile_url('freep.com'))
      ];
  } catch (err) {
      throw err;
  }
  for (let i = 0; i < responses.length; i++) {
      articles = articles.concat(process_response(responses[i]));
  }
  console.log(articles);
}))();

Comparison

Method #ParadigmLoCAvg. IndentMax. Indent
1Callback Hell304.58
2Callback Counter132.24
3Parallel152.14
4Promise131.63
5Coroutine111.32