How to await values being added to array?

62 views Asked by At

I have a project where I am parsing a fast-food menu using Request-Promise and Cheerio, then returning an "order" based on what a user asks for. However, I am having some trouble outputting the "order" which I am storing as an array.

var rp = require('request-promise');
var cheerio = require('cheerio');
var tempMenu = [];
var order = [];

function getItem(item) {

    var itemUrl = baseURL + '/' + item

    var itemMenu = {
        uri: itemUrl,
        transform: function (body) {
            return cheerio.load(body);
        }
    };

    rp(itemMenu)
        .then(function ($) {          
            //.class #id tag
            $(".product-card .product-name a").each(function () {
                tempMenu.push($(this).text());
                order.push(tempMenu[Math.floor(Math.random() * tempMenu.length)]);
                
            });
            console.log(order)
        })

        .catch(function (err) {
        }); 
}

getItem('drinks')
console.log(order)

Currently, the output is:

[]
[
 'drink1',
 'drink2',
 'drink3'
]

If I change the code to the following:

  rp(itemMenu)
        .then(function ($) {          
            //.class #id tag
            $(".product-card .product-name a").each(function () {
                tempMenu.push($(this).text());
                order.push(tempMenu[Math.floor(Math.random() * tempMenu.length)]);
                
            });
            console.log(1)
        })

        .catch(function (err) {
        }); 
}

getItem('drinks')
console.log(2)

The log is

2
1

So I know my problem is the the "order" array isn't filled when I try and output it because it is being logged first, my question is how can I await the array being filled, then output it?

2

There are 2 answers

1
Danziger On BEST ANSWER

Your getItem function should return a Promise and then you can either use the Promise.prototype.then() method on it or the await keyword to make sure you wait for the results before trying to process them.

Here's a simple example with some fake rp function and data:

// Fake:
const rp = (item) => {
  console.log(`Fetching ${ item }...`);
  
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(Math.random());
    }, 1000 + Math.random() * 2000)
  });
}

function getItem(item) {
  const order = [];
  
  // This `getItem` function returns a Promise...
  return rp(item).then((randomNumber) => {          
    for (let i = 0; i < 10; ++i) {
      order.push(`${ item } ${ randomNumber + i }`);
    }
    
    // ...and when this Promise resolves, it will return the `order`
    // array with the right values in it:
    return order;
  });
}

getItem('Drinks').then(order => console.log(order));

console.log('This is executed after calling getItem, but we ware still waiting for the Promise to resolve...');
.as-console-wrapper {
  max-height: none !important;
}

Alternative with async/await:

// Fake:
const rp = (item) => {
  console.log(`Fetching ${ item }...`);
  
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(Math.random());
    }, 1000 + Math.random() * 2000)
  });
}

function getItem(item) {
  const order = [];
  
  // This `getItem` function returns a Promise...
  return rp(item).then((randomNumber) => {          
    for (let i = 0; i < 10; ++i) {
      order.push(`${ item } ${ randomNumber + i }`);
    }
    
    // ...and when this Promise resolves, it will return the `order`
    // array with the right values in it:
    return order;
  });
}

// You can't use `await` outside an `async` function, so we define this first...:
async function loadDataWithAwait() {
  const order = await getItem('Food');

  console.log('This won\'t be executed until getItem\'s Promise is resolved:');
  console.log(order);
}

// ...and now call it:
loadDataWithAwait();
.as-console-wrapper {
  max-height: none !important;
}

0
Eldad Nevo On

The reason it happens is that the then cb function goes to the callback queue. You should wrap them both in an async function with an await on the part you want to wait for.

That should solve you that problem.