Ad

Wait For Firebase Storage Database Pull To Finish Before Rendering Template In Nodejs With Async-await

I am trying to pull some images that are stored in firebase storage, create publicly accessible url's, then add them to an array which will be passed in as I render my template. However, each time my template renders first before the data is pulled and thus the array is empty. I basically need to find a way to render the template only when all the database pull is finished and I don't know how.I have dipped into async-await as a means to try to fix this problem but I have had no luck.

Here is my code:

async function readFiles () {
    const [files] = await bucket.getFiles({ prefix: 'Resources/'});
    files.forEach(file => {

  //we have to get a signed public url in order to access the files stored in the cloud
  file.getSignedUrl(signConfig, function(err, url) {
    if (err) {
      console.error(err);
      return;
    }

    // The file is now available to read from this URL.
    request(url, function(err, resp) {
      resources.push(url) //append all the publicly avaialbe url's to the resources array 
      resp.statusCode = 200;
      console.log("done request")
    });
  });
});

console.log("DONE READ FILES");
}; 


async function returnIndex() {
    await readFiles();  //wait until read files is finished
    console.log("TCL: returnIndex -> resources", resources);
    res.render('advertiser/index.html', {resources: resources});
 };

returnIndex();

And then here is my output(5 things stored in my database), basically indicating that all the public url's are added to the array after my template is rendered:

DONE READ FILES
TCL: returnIndex -> resources []
done request
done request
done request
done request
done request
Ad

Answer

Found a solution. It was to set a timeout for 0 ms... not sure exactly why this works but I think it has to do with the difference in a microtask vs a macrotask on the event loop... Promises are microtasks and Settimeout is a macrotask, so the Settimeout will be executed last and thus the information from the database is pulled correctly

  var resources = new Array(); 

  const [files] = await bucket.getFiles({ prefix: 'Resources/'});

  // Lists all resources in their bucket
  function readFiles () {
    files.forEach(file => {
      file.getSignedUrl(signConfig, function(err, url) {
        if (err) {
          console.error(err);
          return;
        }
        resources.push(url) 
        // The file is now available to read from this URL.
        request(url, function(err, resp) {
          resp.statusCode = 200;
        });
      });
    });
    setTimeout(function(){res.render('advertiser/index.html', {resources: resources})}, 0); 
  };

  readFiles();
Ad
source: stackoverflow.com
Ad