Search code examples
javascriptasynchronousbluebird

Using bluebird promise not working in my created example


I have been studying and trying to understand Asynchronous javascript. After much reading and a suggestion to use the bluebird library because I'm using IE11, I tried it on a simple example I created but it isn't working as expected. I added a settimeout in each function to simulate asynchronicity. The goal is to populate the arrays so I can console.log() the array values but it was to no avail. In my promise.all, I call createNavigation() which suggests that all my arrays are populated but it isn't. Also, numbers are being returned for the results in promise.all.
What am I doing wrong or misunderstanding? Why are my arrays being logged to the console as blanks?

var cacheNavData = [];
var cacheSubNavData = [];
var cacheMegaMenuData = [];
var cacheCategoryMenuData = [];

getNavData();
getSubNavData();
getMegaMenuData();
getCategoryMenuData();

var promises = [
  getNavData(),getSubNavData(),getMegaMenuData(),getCategoryMenuData()
]

Promise.all(promises)
 .then(function(results){
 console.log(results)
 createNavigation()
})
function getNavData(){
   return setTimeout(function(){ 
    cacheNavData[0] = "Soup";
    cacheNavData[1] = "Sandwich";
    cacheNavData[2] = "Rice";  
   }, 3000);
 }

 function getSubNavData(){
   return setTimeout(function(){ 
    cacheSubNavData[0] = "Apple";
    cacheSubNavData[1] = "Beans";
    cacheSubNavData[2] = "Carrot";    
  }, 3000);

 }

 function getMegaMenuData(){
    return setTimeout(function(){ 
    cacheMegaMenuData[0] = "Donkey";
    cacheMegaMenuData[1] = "Eagle";
    cacheMegaMenuData[2] = "Frog";
 }, 3000);
}

function getCategoryMenuData(){
   return setTimeout(function(){ 
    cacheCategoryMenuData[0] = "Grapes";
    cacheCategoryMenuData[1] = "Hand";
    cacheCategoryMenuData[2] = "Igloo";    
   }, 3000);
 }

 function createNavigation(){
   console.log("All arrays have been populated.  Let's build the navigation.")

 }

 console.log(cacheNavData);
 console.log(cacheSubNavData);
 console.log(cacheMegaMenuData);
 console.log(cacheCategoryMenuData);

codepen


Solution

  • That is because in your functions you are returning the ID of the timer, instead of returning a promise that is resolved when the timer runs out. Therefore, the execution is almost immediate. What you want is to ensure that you are returning promises instead of timer IDs in your methods. Here is an example:

    function getNavData(){
       return new Promise(function(resolve) {
         setTimeout(function(){ 
          cacheNavData[0] = "Soup";
          cacheNavData[1] = "Sandwich";
          cacheNavData[2] = "Rice";
    
          resolve();
         }, 3000);
       });
     }
    

    If you want the promise to return data, then instead of using resolve(), you pass the data you want to resolve with as the first argument, e.g. resolve(cacheNavData).

    You should also not be console logging at the end of your file, since those arrays will be empty. If you want to access them, you should read them from results instead, if you are resolving with a payload. You can always use ES6 array spread to unpack the results:

    Promise.all(promises)
     .then(function(results){
      console.log(results);
      const [navData, subNavData, megaMenuData, categoryMenuData] = results;
      console.log(navData, subNavData, megaMenuData, categoryMenuData);
      createNavigation();
    });
    

    This also means that you don't need to declare the global arrays for all your data: your individual functions have the responsibility of passing the populated arrays back to Promise.all.

    See proof-of-concept example:

    var promises = [
      getNavData(),getSubNavData(),getMegaMenuData(),getCategoryMenuData()
    ]
    
    Promise.all(promises)
     .then(function(results){
     console.log(results);
     const [navData, subNavData, megaMenuData, categoryMenuData] = results;
     console.log(navData, subNavData, megaMenuData, categoryMenuData);
     createNavigation();
    })
    function getNavData(){
       return new Promise(function(resolve) {
         setTimeout(function(){ 
          var cacheNavData = [];
          cacheNavData[0] = "Soup";
          cacheNavData[1] = "Sandwich";
          cacheNavData[2] = "Rice";
          
          resolve(cacheNavData);
         }, 3000);
       });
     }
    
     function getSubNavData(){
       return new Promise(function(resolve) {
         setTimeout(function(){
          var cacheSubNavData = [];
          cacheSubNavData[0] = "Apple";
          cacheSubNavData[1] = "Beans";
          cacheSubNavData[2] = "Carrot";
          
          resolve(cacheSubNavData);
        }, 3000);
       });
     }
    
     function getMegaMenuData(){
      return new Promise(function(resolve) {
        setTimeout(function(){ 
          var cacheMegaMenuData = [];
          cacheMegaMenuData[0] = "Donkey";
          cacheMegaMenuData[1] = "Eagle";
          cacheMegaMenuData[2] = "Frog";
    
          resolve(cacheMegaMenuData);
        }, 3000);
      });
    }
    
    function getCategoryMenuData(){
       return new Promise(function(resolve) {
         setTimeout(function(){ 
          var cacheCategoryMenuData = [];
          cacheCategoryMenuData[0] = "Grapes";
          cacheCategoryMenuData[1] = "Hand";
          cacheCategoryMenuData[2] = "Igloo"; 
          
          resolve(cacheCategoryMenuData);
         }, 3000);
        });
     }
    
     function createNavigation(){
       console.log("All arrays have been populated.  Let's build the navigation.")
    
     }