A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.

Here is a quick example:

function greeting(name) {
  alert(`Hello, ${name}`);
}
 
function processUserInput(callback) {
  const name = prompt("Please enter your name.");
  callback(name);
}
 
processUserInput(greeting);

this is synchronous callback;

callback hell

fs.readdir(source, function (err, files) {
  if (err) {
    console.log('Error finding files: ' + err)
  } else {
    files.forEach(function (filename, fileIndex) {
      console.log(filename)
      gm(source + filename).size(function (err, values) {
        if (err) {
          console.log('Error identifying file size: ' + err)
        } else {
          console.log(filename + ' : ' + values)
          aspect = (values.width / values.height)
          widths.forEach(function (width, widthIndex) {
            height = Math.round(width / aspect)
            console.log('resizing ' + filename + 'to ' + height + 'x' + height)
            this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
              if (err) console.log('Error writing file: ' + err)
            })
          }.bind(this))
        }
      })
    })
  }
})

promises https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/async%20%26%20performance/ch3.md

var p = new Promise( function(resolve,reject){
	// `resolve(..)` to resolve/fulfill the promise
	// `reject(..)` to reject the promise
} );
 
var p1 = new Promise( function(resolve,reject){
	reject( "Oops" );
} );
 
var p2 = Promise.reject( "Oops" );
 
var p1 = Promise.resolve( 42 );
var p2 = Promise.resolve( "Hello World" );
var p3 = Promise.reject( "Oops" );
 
Promise.race( [p1,p2,p3] )
.then( function(msg){
	console.log( msg );		// 42
} );
 
Promise.all( [p1,p2,p3] )
.catch( function(err){
	console.error( err );	// "Oops"
} );
 
Promise.all( [p1,p2] )
.then( function(msgs){
	console.log( msgs );	// [42,"Hello World"]
} );
 

async await

The async keyword before a function has two effects:

  1. Makes it always return a promise.
  2. Allows await to be used in it.

The await keyword before a promise makes JavaScript wait until that promise settles, and then:

  1. If it’s an error, an exception is generated — same as if throw error were called at that very place.
  2. Otherwise, it returns the result.

Together they provide a great framework to write asynchronous code that is easy to both read and write.

With async/await we rarely need to write promise.then/catch, but we still shouldn’t forget that they are based on promises, because sometimes (e.g. in the outermost scope) we have to use these methods. Also Promise.all is nice when we are waiting for many tasks simultaneously.