Develop an asynchronous function that can fetch a result at a later time within an Express route

I need to retrieve an Excel file from Box.com using their API and then convert the Excel data into JSON format. Afterwards, I plan to display this JSON data using Express and Handlebars.

Below is the function I've created for fetching the Excel file and converting it to JSON:

let getExternalData = async () => {
  const stream = await client.files.getReadStream('123456789');
  const externalFile = await fs.createWriteStream('/external.xlsx');
  
  stream.pipe(externalFile);
  
  let finished = await externalFile.on('finish', async () => {
    const excelData = await excelToJson({
      source: fs.readFileSync(externalFile.path),
      header: {
        rows: 1
      },
      columnToKey: {
        A: "edate",
        B: "esource"
      },
      sheets: ['Sheet1']
    });
    
    console.log(excelData);
    return excelData;
  })
}

My current issue is that I am unsure how to handle the pending Promise when calling the function like this:

let testData = getExternalData();
console.log(testData); // Promise { <pending> }

I intend to use this function to download multiple files and store them in variables to be passed to my express route later on.

app.get('/', (req, res) => {
    res.render('stories.ejs', {
        msg: "Welcome to stories.ejs", 
        odata: odata, 
        edata: edata,
        ...
    });
});

Would wrapping it in an anonymous async function be a solution?

Answer №1

async/await is not a one-size-fits-all solution for handling asynchronous operations. These keywords were specifically designed to work with Promises and do not function properly with event emitters. To correctly implement the getExternalFile function, follow this updated code snippet:

let getExternalFile = async () => {
  const stream = client.files.getReadStream('123456789'); // no await here
  const external = fs.createWriteStream('/external.xlsx'); // no await here
  stream.pipe(external);

  let finished = new Promise ((resolve, reject) => {
    external.on('finish', async () => { // cannot use await here
      const excel = await excelToJson({
        source: fs.readFileSync(external.path),
        header: {
          rows: 1
        },
        columnToKey: {
          A: "edate",
          B: "esource"
        },
        sheets: ['Sheet1']
      });
      console.log(excel);

      resolve(excel);
    })
  });

  return finished; // return the promise so you can await it later
}

Functions that are not Promises are incompatible with await, including event emitters like x.on('some_event' ... ). In such cases, you must wrap them in new Promise() to convert them into Promises.

Once the above function has been rewritten, you can easily await the result:

app.get('/', async /* <--IMPORTANT */ (req, res) => {
    let testData = await getExternalFile(); // use await here!!

    // ...
});

If multiple awaits slow down your function, consider executing async functions in parallel using Promise.all():

app.get('/', async /* <--IMPORTANT */ (req, res) => {
    let testDataArray = await Promise.all([
        getExternalFile(), getExternalFile2()  // FAST!
    ]);

    // ...
});

Epilogue: Dealing with Errors

In real-world scenarios, always handle errors on awaited code to prevent server crashes:

app.get('/', async /* <--IMPORTANT */ (req, res) => {
    try {
        let testData = await getExternalFile(); // use await here!!

        // ...
    }
    catch (err) {

        // ...
    }
});

Alternatively, utilize middleware like express-async-handler to manage async errors effectively.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide on sending AJAX requests from Javascript/React to Python REST API and receiving data

In my project, I have developed the front end code using React. There is a simple form where users can input their name, title, department, and other basic string fields. Upon hitting submit, JavaScript triggers an AJAX request to my REST API which is impl ...

Disappearing Facebook share button: A common occurrence when navigating in Nuxt.js (Vue.js)

Within my nuxt.js web app, utilizing version 2.15.7, I have integrated a Facebook share button by following the instructions outlined in this comprehensive code example. Upon initial load of the application, the Facebook share button appears as expected. ...

Is Passport.js' serializeUser and deserializeUser functions never triggering?

Encountering an issue with Passport-local. It seems that neither serializeuser nor deserializeUser are being invoked. Upon researching similar problems on SO, it appears that many others facing this problem were not properly including bodyParser. Below is ...

The image loads successfully from an AJAX request in CodePen, but fails to load in the local

I am currently working on integrating a weather API into my basic website and I would like to incorporate the weather icons as well. The API request successfully works in both my local and live environments, however, I encounter an error with the icon spec ...

Challenges with loading times in extensive AngularJS applications

We are currently tackling performance issues related to the loading time of our AngularJS application. The page takes a significant amount of time to load, and we are exploring potential causes for this delay. One factor that could be contributing to the ...

What is causing the fs.readFile function to give back undefined instead of the expected result?

/** * A function to determine the cost of an employee from a specific data file * @param {string} filePath - the path to the employee data file * @returns {{name: string, cost: number}} - the name and cost of the employee */ function calculateEmployee ...

Executing a raw query within an express.js route using sequelize

I'm currently a beginner in using sequelize. I have a node.js project set up with sequelize cli and am attempting to execute a raw query within a "put" express route of my application. However, I keep encountering an error: Sequelize.query is not a ...

Show a variety of pictures in a random arrangement?

Looking for some help here! I'm trying to shuffle my images in a random order each time the page is refreshed. It's like a game of musical chairs but with pictures! Does anyone know how to achieve this? I've done some searching, but haven& ...

Working with jQuery, CSS, and functions to modify the current tag's class

Let's keep it brief and straightforward: Here is my HTML <div id="headerVideoControls" class="overlayElement"> <div id="videoMuteUnmute" onclick="muteUnmuteVideo('headerVideo')">mute button</div> </div> Edited ...

Error in Displaying Vuetify Child Router View

I am currently working on integrating a child router-view to be displayed alongside surrounding components. Here is an overview of my routing setup: { path: "/login", name: "TheLoginView", component: TheLoginView, }, { path: "/dashboa ...

React- hiding div with hover effect not functioning as expected

I'm having trouble using the :hover feature in CSS to control the display of one div when hovering over another, it's not functioning as expected. I've successfully implemented this on other elements, but can't seem to get it right in t ...

Send JSON data that has been refined utilizing jQuery

I am attempting to create a filtered JSON response using jQuery following a successful GET request of the original JSON response. The initial JSON response is an array of products from our Shopify store for the specific collection page the user is viewing. ...

Modal's ng-click not triggering component's function

I am currently working on resolving an issue. My choice to use AngularJS is intentional, as I prefer not to load the entire NPM of Angular. Additionally, we heavily rely on Razor Syntax for the Web Layer. Implementation in Create.cshtml file <button ...

JWT triggers a JsonWebTokenError with the message "token is not valid"

I implemented token verification in my Node Application using jsonwebtoken. The issue I'm facing is that while jwt.sign works perfectly, jwt.verify is throwing the following error: "auth": false, "message": { "name": "JsonWebTokenEr ...

Durandal attempts to retrieve a view located within the viewmodel directory

Having an issue with durandal's compose binding as it is looking for views under app/viewmodels instead of app/views The ViewModel code: define(["fields/fieldClosures"], function (fields) { var ctor = function(opt) { this.value = opt.valu ...

The success function is failing to display the Ajax response

Is there a way to correctly display the ajax response of my code? I noticed that when using async=true, only the last value of yy is shown. However, I want to display it for all values from 0 to a. Interestingly, everything works fine when using async=fa ...

Move the option from one box to another in jQuery and retain its value

Hey guys, I need some assistance with a jQuery function. The first set of boxes works perfectly with the left and right buttons, but the second set is not functioning properly and doesn't display its price value. I want to fix it so that when I click ...

Customized style sheets created from JSON data for individual elements

One of the elements in the API requires dynamic rendering, and its style is provided as follows: "elementStyle": { "Width": "100", "Height": "100", "ThemeSize": "M", "TopMargin": "0", " ...

Transitioning the style code from inline to the head of the document disrupts the straightforward JavaScript intended to

As I delve into the world of web development, I encountered a simple issue that has been causing me frustration for the past hour. It involves code to display the border color of a div element using an alert. The code works perfectly fine when the style is ...

Extract reference value from an HTML element

Is there a way to access the ref prop from an HTML element using Testing Library React? My current code snippet is as follows: it('element container ref should be null if prop noSwipe is passed', () => { const onCloseMock = jest.fn() ...