I often find myself tempted to reach for tools like Caolan McMahon's https://github.com/caolan/async when all I have to do is simply run a few easy callbacks in sync.

Here is a simple trick to flatten sequenced callbacks without resorting to enlarging the dependency surface of your app and pulling in functionality you don't need.

Alternative to async

First chuck the following function in your utils somewhere:

function sequence(...cbs) {  
  return new Promise((resolve, reject) => {
    cbs.push(() => resolve());
    function next() {
      const done = (err) => err ? reject(err) : next();
      cbs.length && cbs.shift()(done);
    }
    next();
  });
}

Sequence those callbacks!

You can then use it like this:

const callback1 = (done) => {  
  console.log('one...');
  setTimeout(() => {
    console.log('one');
    done();
  }, 1000);
}

const callback2 = (done) => {  
  console.log('two...');
  setTimeout(() => {
    console.log('two');
    done();
  }, 1000);
}

const callback3 = (done) => {  
  console.log('three...');
  setTimeout(() => {
    console.log('three');
    done();
  }, 1000);
}

// Promise version
sequence(callback1, callback2, callback3)  
  .then(() => console.log('Done!!'))
  .catch((err) => console.error(err));

// Callback version
sequence(callback1, callback2, callback3, (err) => {  
  if(err) {
    throw new Error('Go crazy!');
  }
})