We will discuss the benefits and use case for each of the paradigm.


  1. Callback is a Higher-order Function
  2. Came as part of ES5
  3. Callback functions are derived from a programming paradigm known as functional programming
  4. Problem: Pyramid of Doom / Callback Hell – when too many callbacks are nested in one another, it becomes difficult to understand and predict the code.

example of simple callback

function One(a, cb){

One(4, (val)=> { //callback function


  1. Use promises whenever you are using asynchronous or blocking code.
  2. Each promise is immutable
  3. Came as part of ES6
  4. Promises are used to avoid callback doom
  5. Promises are more powerful than callback as they are compose-able
  6. To run promises in parallel create an array of promises and then use Promise.all(promisesArray)
  7. Promise methods: Promise.prototype.catch(onRejected) Promise.prototype.then(onFulfilled, onRejected) Promise.prototype.finally(onFinally)
  8. Static methods:  Promise.reject(reason) Promise.resolve(value) Promise.all(iterable) Promise.race(iterable)
const myFirstPromise = new Promise((resolve, reject) => {
  // do something asynchronous which eventually calls either:
  //   resolve(someValue); // fulfilled
  // or
  //   reject("failure reason"); // rejected


  1. Came as part of ES6
  2. Generators are functions that you can use to control the iterator. They can be suspended and later resumed at any time.
  3. Yield returns a value only once, and the next time you call the same function it will move on to the next yield statement.
  4. Generators achieve yield delegation using chaining
  5. Generators return iterators, and it means we can actually iterate over it synchronously.
//ways of declaring generators

function * generator () {}
function* generator () {}
function *generator () {}

let generator = function * () {}
let generator = function* () {}
let generator = function *() {}

let generator = *() => {} // SyntaxError
let generator = ()* => {} // SyntaxError
let generator = (*) => {} // SyntaxError

class MyClass {
  *generator() {}
  * generator() {}

const obj = {
  *generator() {}
  * generator() {}
function * generator() {
  yield 5;

const gen = generator();

gen.next(); // {value: 5, done: false}
gen.next(); // {value: undefined, done: true}
gen.next(); // {value: undefined, done: true}

For React Devs: Redux saga makes use of generators in sagas

function* ourSaga() {
  yield take('START_REGISTRATION');
  yield put(showLoginPopup());



  1. async function returns promise implicitly
  2. Came as part of ES7
  3. The async function automatically knows what to do if you await a Promise—it will pause the function (just like with generators) until the Promise resolves
  4. async await makes it much more easier to use promises. Developers from synchronous programming background will feel at home while using asyncand await
  5. await blocks the execution of the code within the async function in which it is located.
  6. If the output of function2 is dependent on output of function1 then I use await.
  7. If two functions can be run in parallel create two different async functions and then run them in parallel.
  8. Promise creation starts the execution of asynchronous functionality.
  9. An asynchronous function is a function which operates asynchronously via the event loop, using an implicit Promise to return its result.
  10. Every time you use await remember that you are writing blocking code. Over the time we tend to neglect this.
  11. If your code contains blocking code it is better to make it an asyncfunction. By doing this you are making sure that somebody else can use your function asynchronously.
function resolveAfter2Seconds() {
  return new Promise(resolve => {
    setTimeout(() => {
    }, 2000);

async function asyncCall() {
  var result = await resolveAfter2Seconds();
  // expected output: 'resolved'