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

JavaScript - Need to automatically scroll to a different div when scrolling occurs

Currently, my focus is on creating a single-page website where the main content is displayed in large boxes arranged vertically down the page. If you have any suggestions or thoughts on using JavaScript to navigate to each content box more efficiently, I ...

Despite the value being true, the if statement does not work when used with a Mongoose object in Node.js

Currently working on a bidding app, Below is the schema for the bidding model const bidSchema = new mongoose.Schema({ name: String, price : Number, description: String, location: String, specilization: String, image: String, ...

Is it possible to use the Stop Button on the HTML5 Audio Tag to halt a live MP3 stream

Is there a way to add a stop button as well? Currently, I have play and pause buttons, but the stop function doesn't truly clear the music buffer in the browser; it just stops playback without resetting to the beginning. This is fine for MP3 files but ...

Exploring the Depths of the DOM: Enhancing User Experience with Jquery

I am facing an issue with my AJAX request in my page. After retrieving data from the database and trying to append it to a div, I am attempting to create an accordion interface without success. Below is a snippet of my source code after the AJAX call: ...

Implementing Basic Authentication with Express and Mongoose

I am in the process of implementing basic authentication for my Express paths. In order to verify if the user/password combination is correct, I am reading the usermodels collection from my MongoDB database. Below is the code snippet: server.js var norma ...

To collapse a div in an HTML Angular environment, the button must be clicked twice

A series of divs in my code are currently grouped together with expand and collapse functionality. It works well, except for the fact that I have to click a button twice in order to open another div. Initially, the first click only collapses the first div. ...

choosing a section within a table cell

This seems like a simple task, but I'm encountering some difficulties $("#info-table tbody tr").each(function(){ $(this).find(".label").addClass("black"); }); .black{ font-weight:bold; } <script src="https://ajax.googleapis.com/ajax/libs/j ...

Modify the values of an object by utilizing the setter function

How can I utilize the setter method to update existing values of an object and perform mathematical operations? var obj = { set model(object) { //method's logic } }; obj = {x:10, y: 20, p: 15}; obj = { x:10, y: 20, p: 15 set mod ...

An issue has been identified where the Export to Excel and PDF functionality is not functioning properly within a Datatable after applying a

I am using multiple select option filtering with ajax, jQuery, and PHP in a datatable. The records are being filtered correctly, but after changing the select option, the Export to Excel/ PDF functionality is not working properly. Note:- (1) It always do ...

Error: The build process for Next.js using the command `npm run build`

Currently attempting to construct my application with target: 'serverless' set in the next.config.js file (in order to deploy on AWS Lambda). Upon running npm run build, I am encountering the following output: Warning: Built-in CSS support is bei ...

Tips for generating a single sitemap in Next.js

Utilizing the next-sitemap package to generate a sitemap, I have both dynamic and static pages. This is what my next-sitemap.config.js file looks like: module.exports = { siteUrl: 'https://example.com', generateRobotsTxt: false, excl ...

There was an error in reading the 'nativeElement' property in Angular's waveform library, resulting in a TypeError

This is the code I wrote, but it is showing an error: The waveform should be created, but the function to create the waveform is not working. startRecording() { this.mediaSectionVisible = false; if (!this.isRecording) { this.isRecording = t ...

What is the reason behind the NodeJS domains documentation code attempting to end the process?

The official NodeJS documentation provides a code example where the process attempts to exit gracefully in the event of an exception occurring in the domain. It closes connections, waits for other requests, and then exits. But wouldn't it be simpler ...

Error: Cannot locate 'import-resolver-typescript/lib' in jsconfig.json file

Issue: An error occurred stating that the file '/Users/nish7/Documents/Code/WebDev/HOS/frontend/node_modules/eslint-import-resolver-typescript/lib' could not be found. This error is present in the program because of the specified root file for c ...

AngularJS form submission with and without page refresh

Looking to implement an AngularJS form directive where, if on /home page, redirect to /search/term and if already on /search page, submit without refreshing the page by simply changing the location. I am able to do both separately, but struggling to writ ...

The npm command encountered a permission issue when trying to install node-sass

Whenever I run the npm command on my Ubuntu system, I encounter a "permission denied" issue. sudo npm install node-sass EACCES: permission denied, access '/node_modules/node-sass' I have attempted to run the command as a root user or with sudo ...

Leveraging the combination of Express JS and Vue.js within the Electron framework

Can you combine Vue.js and Express JS in a project with Electron JS? How would this work? I currently have a project running on Vue.js and Electron JS, but I'm unsure how to integrate Express JS into it. Any guidance would be greatly appreciated. ...

Guide on creating a project for developing an npm package

Within my git root project, I am utilizing a git subproject called UIComponents. For instance, my main project is named MyApp and the subproject is UIComponents. Currently, I have cloned the UIComponents repository inside my project folder and added UIComp ...

What is the process of transforming a JSON string into a JavaScript date object?

{"date":"Thu Dec 06 14:56:01 IST 2012"} Is it possible to convert this JSON string into a JavaScript date object? ...

Disregarding text within an express route

I am currently working with the following routes: app.get('/blah/query.json', doSomething); app.get('/blah/:id.:format', doSomethingElse); At the moment, both routes are being triggered so that route one (query.json) is called first f ...