Writing a user's profile image to disk using nested Node.JS closures
First of all, you are correct. One way to prevent deep nesting is to pull out the callback into it's own named function. This allows you to only be as deep as 2-3 levels in blocks of code.

function task1(){
  async1(task2);
}

function task2(){
  async1(task3);
}

function task3(){
  async1(task4);
}


Another way to do it is by using flow-control libraries which take advantage of the concept of Futures/Deferreds/Promises. There are a lot of ways to call them, but they are the same thing most of the time.

The basic concept is that they usually stack up callbacks via utility functions and then run them, depending on the result of the previous or depending on the used utility function. The code will look linear and synchronous, but it actually is running async and the library controls the flow of calls and results. In jQuery, you can do something like

//Run an addition in the server
$.get('add.php',{
    op1 : 1,
    op2 : 2
  })
  .then(function(result){
    //get the addition result (3) and multiply it on the server (another async)
    return $.get('multiply.php'{
      op1 : result,
      op2 : 3
    });
  })
  .then(function(result){
    //get the multiplication result (9) and divide it on the server (another async)
    return $.get('divide.php'{
      op1 : result,
      op2 : 9
    });
  })
  .done(function(result){
    console.log(result); //1
  });