Promise Chaining

Objectives

  • Describe the disadvantages of using nested callbacks

  • Return a promise from a .then callback function

  • Use a promise to make asynchronous code seem sequential

Nested Async Callbacks

 var counter = 0;
 setTimeout(function() {
   counter++;
   console.log("Counter:", counter);
   setTimeout(function() {
     counter++;
     console.log("Counter:", counter);
     setTimeout(function() {
       counter++;
       console.log("Counter:", counter);
     }, 3000);
   }, 2000);
 }, 1000);

Console:

Counter: 1

Counter: 2

Counter: 3

Disadvantages of Nested Callbacks

  • The code is hard to read

  • Logic is difficult to reason about

  • The code is not modular

Returning a Promise:

Promise Chaining

var promise = new Promise(function(resolve, reject) {
  setTimeout(function() {
    randomInt = Math.floor(Math.random() * 10);
    resolve(randomInt);
  }, 500);
});

promise.then(function(data) {
  console.log("Random int passed to resolve:",
               data);
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(Math.floor(Math.random() * 10));
    }, 3000);
  });
}).then(function(data) {
  console.log("Second random int passed to resolve:",
               data);
});

Promise Chaining:

Returning Data

 var promise = new Promise(function(resolve, reject) {
   resolve(5);
 });

 promise.then(function(data) {
   return data * 2;
 }).then(function(data) {
   return data + 20;
 }).then(function(data) {
   console.log(data);
 });

Console:

30

Nested Callbacks:

To Be Refactored

 

 var counter = 0;
 setTimeout(function() {
   counter++;
   console.log("Counter:", counter);
   setTimeout(function() {
     counter++;
     console.log("Counter:", counter);
     setTimeout(function() {
       counter++;
       console.log("Counter:", counter);
     }, 3000);
   }, 2000);
 }, 1000);

Console:

Counter: 1

Counter: 2

Counter: 3

Step 1:

Create a Function Declaration

 

 var counter = 0;
 function incCounter() {
   counter++;
   console.log("Counter:", counter);
 }

Step 2:

Create a runLater Function

 var counter = 0;
 function incCounter() {
   counter++;
   console.log("Counter:", counter);
 }

 function runLater(callback, timeInMs) {
   var p = new Promise(function(resolve, reject) {
     setTimeout(function() {
       var res = callback();
       resolve(res);
     }, timeInMs);
   });
   return p;
 }

Step 3: Chain Promises

 var counter = 0;
 function incCounter() {
   counter++;
   console.log("Counter:", counter);
 }

 function runLater(callback, timeInMs) {
   var p = new Promise(function(resolve, reject) {
     setTimeout(function() {
       var res = callback();
       resolve(res);
     }, timeInMs);
   });
   return p;
 }

 runLater(incCounter, 1000).then(function() {
   return runLater(incCounter, 2000);
 }).then(function() {
   return runLater(incCounter, 3000);
 }).then(function() {
   // final .then not necessary
 });

Promise Refactor: Side By Side

 var counter = 0;
 function incCounter() {
   counter++;
   console.log("Counter:", counter);
 }

 function runLater(callback, timeInMs) {
   var p = new Promise(function(resolve, reject) {
     setTimeout(function() {
       var res = callback();
       resolve(res);
     }, timeInMs);
   });
   return p;
 }

 runLater(incCounter, 1000).then(function() {
   return runLater(incCounter, 2000);
 }).then(function() {
   return runLater(incCounter, 3000);
 });
 var counter = 0;
 setTimeout(function() {
   counter++;
   console.log("Counter:", counter);
   setTimeout(function() {
     counter++;
     console.log("Counter:", counter);
     setTimeout(function() {
       counter++;
       console.log("Counter:", counter);
     }, 3000);
   }, 2000);
 }, 1000);

It is useful to understand how promises work (resolve, reject), but in practice you will often use promises that are returned to you

Promises In Practice

Promise Chaining

By Elie Schoppik

Promise Chaining

  • 2,872