JavaScript Callback vs Promis vs Generators

js_promis_callback_generators

Callback

A callback is a function that will be executed when an asynchronous operation has been completed.

function sayHello(){
 console.log('Hello');
}

setTimeout(sayHello, 1000);

Since setTimeout is asynchronous operation, sayHello function can be considered as callback function. because after 1000 millisecond, setTimeout function will call sayHello function.

Promise

Promise was introduced in ES6 and It accepts two parameters in constructor resolve and reject.

let promise = new Promise(function(resolve, reject) {
    if(/* everything successful */) {
        resolve('Successful')
    } else {
        reject('it broke')
    }
})

Not like callback, Promise has three states,
PendingInitial state, neither fulfilled nor rejected.
Fulfilled – meaning that the operation completed successfully.
Rejected – meaning that the operation failed.

Promise.all() helps to group array of promises into one promise, finally it will be resolved if all promises are passed, otherwise it will be rejected.

Promise.all([
    new Promise((resolve, reject) => setTimeout(() => resolve('one'), 3000)),
    new Promise((resolve, reject) => setTimeout(() => resolve('two'), 2000)),
    new Promise((resolve, reject) => setTimeout(() => resolve('three'), 1000)),
]).then(result => console.log(result)) // one, two, three

Promise.race() helps to group array of promises into one promise, but it will be resolved if anyone of sub promise is passed otherwise, rejected with value or reason of immediately failed sub promise.

Promise.race([
    new Promise((resolve, reject) => setTimeout(() => resolve('one'), 3000)),
    new Promise((resolve, reject) => setTimeout(() => resolve('two'), 2000)),
    new Promise((resolve, reject) => setTimeout(() => reject('three'), 1000)),
]).then(result => console.log(result)) // Uncaught (in promise) three

Promise Chaining

One of main advantage of using promise is Promise Chaining, The idea is that the result of promise is passed through chain of .then handlers. There are two way of doing promise chaining.

new Promise(function(resolve, reject) {

  setTimeout(() => resolve(1), 1000); // (*)

}).then(function(result) { // (**)

  console.log(result); // 1
  return result * 2;

}).then(function(result) { // (***)

  console.log(result); // 2
  return result * 2;

}).then(function(result) {

  console.log(result); // 4
  return result * 2;

});
let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 1000);
});

promise.then(function(result) {
  console.log(result); // 1
  return result * 2;
});

promise.then(function(result) {
  console.log(result); // 1
  return result * 2;
});

promise.then(function(result) {
  console.log(result); // 1
  return result * 2;
});

Generators

In Javascript, normal function can not be paused in middle of execution, but generator is a function that can stop midway and then continue from where it stopped. Generator function was introduced in ES6.

function* gen() { 
  yield 1;
  yield 2;
  yield 3;
}

var g = gen();  // gen() function will create generator object

console.log(g.next());  // {value: 1, done: false}
console.log(g.next());  // {value: 2, done: false}
console.log(g.next());  // {value: 3, done: false}
console.log(g.next());  // {value: undefined, done: true}

As you can see here, generator function can be iterated with a .next() method and it will return object with value and state. Generator has very unique behavior other than regular function or promise. You can use generator function with for...of statement 

What will happen if we use Generator function with Promise. It looks like Async/Await function in ES8. But keep in mind that both Generator and Async/Await functions are different way of handling a function.

Use case 1 – Let say, we need a loop that has infinite iteration, so we can use Generator function. This solution is good for handling pagination on page or grid.

function *doWhile(){
  var counter = 0;
  
  // infinite loop!
  while (true){

    // yield to the generator iterator
    yield counter;
    
    // then increment and reset regularly
    counter += 1;
    if (counter > 100000) {
      counter = 0;
    }
  }
}

Use case 2 – Since it is recursion, We can solve Fibonacci number easily.
e.g. 0, 1, 1, 2, 3, 5, 8, 13, 21, 34,

function* fib() {
  let a = 0, b = 1;
  while (true) {
    yield a;
    [a, b] = [b ,a + b];
  }
}

var fib = fib();
fib.next(); //{value: 0, done: false}
fib.next(); //{value: 1, done: false}
fib.next(); //{value: 1, done: false}
fib.next(); //{value: 2, done: false}
fib.next(); //{value: 3, done: false}
fib.next(); //{value: 5, done: false}

To Summarize.

Callback and Promises are much similar, but Promise can be used chaining methods one after another. It has separator state for any rejection. However, Generator function is completely different than the Promise and Callback. Generator function can be paused in middle of the execution and can be used with for...of statement.

Leave a Reply