简体   繁体   中英

Async await in Express middleware not working

I'm a bit of newbie to Node so be gentle. I'm creating an app for my wedding which takes an uploaded guestlist (in Excel file format) and turns it into a JSON array which I can then use to build profiles about each guest (dietary requirements, rsvp answer, etc).

So far I've got a form on the homepage which allows the user to upload the .xlsx file and when the form is submitted the user is redirected back to the homepage again.

I've created the following route:

router.post('/',
    guestsController.upload,
    guestsController.getGuestlist,
    guestsController.displayGuestlist
);

and here's my guestsController:

const multer = require('multer');
const convertExcel = require('excel-as-json').processFile;

const storage = multer.diskStorage({ //multers disk storage settings
    destination: function (req, file, cb) {
      cb(null, './uploads/')
    },
    filename: function (req, file, cb) {
        var datetimestamp = Date.now();
        cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length -1])
    }
});

exports.upload = multer({storage: storage}).single('file');

exports.getGuestlist = async (req, res, next) => {

  try {
     await convertExcel(req.file.path, null, null, (err, guestData) => {
         req.guestlist = guestData.map((guestObj) => Object.values(guestObj)[0]);
     });
     console.log(req.guestlist);
     next();
  } catch (e){
    res.json({error_code:1,err_desc:"Corrupted Excel file"});
    next();
  }
};

exports.displayGuestlist = (req, res) => {
    console.log(req.guestlist);
};

At the moment because of the synchronous nature of the functions, displayGuestlist is returning undefined to the console because covertExcel has not finished grabbing the data. You can see I have tried to use the new async await syntax to resolve this but it hasn't fixed it unfortunately.

I have also tried putting the log in displayGuestlist in a timeout function which has proven that this is purely a timing issue.

Any helpers would be much appreciated.

It looks like convertExcel is not a Promise-returning function, but rather uses an old-school callback. await does not work with those, so it's instead awaiting Promise.resolve(undefined) since the function returns undefined , not a Promise. Thankfully, in Node 8 and later, there's a promisify utility to convert callback-style functions to Promise-returning functions so that await can be used.

const { promisify } = require('util');
const convertExcel = promisify(require('excel-as-json').processFile);

// ...

const guestData = await convertExcel(req.file.path, null, null);
req.guestlist = guestData.map((guestObj) => Object.values(guestObj)[0]);

You can encapsulate your code in a promise and await this promise to resolve.

exports.getGuestlist = async (req, res, next) => {
let promise = new Promise((resolve, reject) => {
    convertExcel(req.file.path, null, null, (err, guestData) => {
        if(err) reject(err);
        else resolve(guestData);
    });
});
try {
    let guestData = await promise;
    req.guestlist = guestData.map((guestObj) => Object.values(guestObj)[0]); 
    console.log(req.guestlist);
    next();
} catch (e){
    res.json({error_code:1,err_desc:"Corrupted Excel file"});
    next();
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM