max-mapper / callback-hell

information about async javascript programming
http://callbackhell.com
847 stars 100 forks source link

Mention async.js #8

Open darobin opened 12 years ago

darobin commented 12 years ago

Good stuff! I think it's worth also mentioning async.js (https://github.com/caolan/async/). I use it a lot to keep async stuff in check, especially parallel().

max-mapper commented 12 years ago

first and foremost I want to cover simple and 'pure js' solutions to common problems without resorting to third party libs.

however I also use async in certain cases and see the value in libraries that let you run a callback on a group of callbacks

jquery deferreds do it like this (syntax from memory):

$.when(promise, promise, promise).then(callback)

async does it like this:

async.parallel([function, function, function], callback)

minimal libs like queue do it like this:

queue(1).defer(function).defer(function).defer(function).await(callback)

at a high level these are the same pattern. async has lots of options and flavors, queue is very minimal at 554 bytes, jquery deferreds are syntax heavy and complex but also pervasive

maybe i could distill these thoughts into a description of the 'callback for many callbacks' problem somehow?

max-mapper commented 12 years ago

heres a simplified version of the question:

say you want to download two cat photos and combine them into one cat photo:

downloadKitten('http://placekitten.com/200/600', firstKitten)
downloadKitten('http://placekitten.com/200/300', secondKitten)

whats the simplest way to get both kittens in one callback?

max-mapper commented 12 years ago

naive implementation:

function waitForTwoCats(catURL1, catURL2, callback) {
  var first, second
  function firstKitten(firstCat) {
    first = firstCat
    if (second) callback(first, second)
  }
  function secondKitten(secondCat) {
    second = secondCat
    if (first) callback(first, second)
  }
  downloadKitten(catURL1, firstKitten)
  downloadKitten(catURL2, secondKitten)
}

obviously there are problems with this but the goal is to show when you need third party libs and when you dont. is this the simplest way to show the complexity of the problem?

jrburke commented 12 years ago

For me, the other case of callback hell, besides "wait till this set of async things finish" and nested callbacks is code that has conditionals. Suppose that there are some steps, some of which need to happen async, but some that can be skipped if a value is available already.

function step3(value) {
   //Do step 3
}

function step2(value) {
  //Do step 2
   step3(value);
}

function step1() {
    //Do step 1
    step2(value);
}

if (alreadyHaveValue()) {
       step2(existingValue);
   } else {
      step1();
   }
}

For me, that is when something like promises or some library with a .then() which allows processing plain values or deferred promises, comes in useful. Using q:

Q.fcall(function () {
    if (alreadyHaveValue()) {
        //Existing value is not a promise
        return existingValue;
    } else {
        return step1ReturningPromiseOrJustInlineHere();
    }
}).then(function (value) {
    //Do step 2, could have conditionals
}).then(function (value) {
   //Do step 3, could have conditionals
}); 

It gives a more linear read of the logic flow.

No need for inside out, functions with names that are jumped to for the next step. That is too reminiscent of goto.

mixu commented 12 years ago

I hate plugging my own solutions, but hey, you asked on Twitter. Maybe you can reduce this problem into three basic functions, series(), parallel() and limited()? http://book.mixu.net/ch7.html

Would love a link back if you do use it, though these days I'd write a lot of that stuff differently, works though.

htchaan commented 9 years ago

I think async.js certainly worth some words. https://www.npmjs.com/package/async: 9,178,397 downloads in the last month https://www.npmjs.com/package/q: 3,664,443 downloads in the last month https://www.npmjs.com/package/promise: 745,687 downloads in the last month

And the link to @mixu's book is now http://book.mixu.net/node/ch7.html.