0

am using await inside await, first i have used await in line 'a', it works fine and enters inside continues to execute from line 'b' to line 'd', but after that it needs to go inside that query and has to execute from line 'e' to line 'f', then it has to execute line 'g' and 'h' finally and return result but problem is after line 'd' it will not execute inside code instead it comes to line 'g' and executes further code and then comes back to line 'e' which causes error. Please help me out.


    var writeStreamData = '';
    var surveyBlockId = req.body.surveyBlockId;
    var title = req.body.title;
a.    await SurveyAnswer.find({'blockId': surveyBlockId}, (err, doc) => {
b.        if(doc.length!=0){
            userName = '';
            userIdList = Object.values(doc.reduce((acc,cur)=>Object.assign(acc,{[cur.userId.toString()]:cur}),{}));
            const pdfDoc = new PDFDocument({margin: 50});

            writeStreamData = pdfDoc.pipe(fs.createWriteStream('pdf_files/SurveyAnsweredUserList.pdf'));

            pdfDoc.fontSize(25).text('Home Owners Association', {align: "center"});
            pdfDoc.lineCap('butt').moveTo(30,80).lineTo(600,80).stroke();
            pdfDoc.moveDown();
            pdfDoc.fontSize(20).text('Survey Title : '+title);
            pdfDoc.moveDown();
            pdfDoc.fontSize(20).text('List of Users');
            if(doc.userIdList!=0){
                var counter = 0;
c.                userIdList.forEach(async element => {
                    userId = element.userId.toString();
d.                    await User.findOne({'_id':userId},async(err1, doc1) => {
e.                        if(!err1){
                            counter++;
                            userName = doc1.firstname + " "+ doc1.lastname;
                            pdfDoc.fontSize(15).text((counter)+". "+userName).moveDown();
                        }else{
                            counter++;
                            //return eachCb(err1)
                        }
                        //eachCb();
                    })
                }, function(err, data) {
                    if(err){
                        response = {
                            "message": "failed"
                        }
                        res.send(response);
                    }
                });
            }else{
                pdfDoc.fontSize(15).text('No User answered');
            }
f.            pdfDoc.end();
        }else{
            response = {
                "message": "failed"
            }
            res.send(response);
        }
    });

g.    fs.readFile(writeStreamData.path, function(err, data) {
h.        if(err) throw err;
        const pdf = data.toString('base64');
        response = {
            "message": "success",
            "data": pdf
        }
        res.send(response);
    })   
});```

3 Answers3

1

You are doing a few things wrong. You can only await a promise. SurveyAnswer.find() receives a callback function, it doesn't return a promise. So, you can't await it. Same goes for d and g. As you are using callback style so await in front of a, d and g is useless.

Also, await does not work in forEach function. Use for...of instead.

Shihab
  • 2,641
  • 3
  • 21
  • 29
  • router.post('/downloadSurveyListPdf', async(req, res) => { var writeStreamData = ''; await SurveyBlock.find((err, doc) => { const pdfDoc = new PDFDocument({margin: 50}); }); fs.readFile(writeStreamData.path, function(err, data) { res.send(response); }) }); here is my another code here i used await befor SurveyBlock.find() then only line 'g' executed after, but if i remove await line 'g' will execute first then it comes inside SurveyBlock.find() which causes error – Shashank Shetti Jan 16 '20 at 13:09
0

In my opinion the cleanest way is to write wrappers for functions like fs.readFile that return a promise instead of using a callback. This makes it easier to compose everything with await.

You can use bluebird to automate this conversion as shown in this answer: https://stackoverflow.com/a/34642827/303637

Peter Zeller
  • 2,245
  • 19
  • 23
0

You can make use of Promise inside Promise instead of async await to get your work done. I have an example similar to yours which i am using to fetch data from s3 bucket. You can take reference to implement promise inside promise.

 new Promise((lresolve) => {
        s3.listObjectsV2(params, (err, devicedata) => {
            if (!err) {
                const data = devicedata.CommonPrefixes;
                data.forEach(value => {
                    const prefix = value.Prefix.replace(params.Prefix, '').replace('/', '');
                    devices.push(prefix);
                });
                lresolve(devices);
            }
        });
    }).then(qDevices => {
        const devicePromise = [];
        qDevices.forEach(devicepath => {
            devicePromise.push(
                new Promise((qresolve) => {
                    params.Prefix = `${staticPrefix + devicepath}/tyre/`;
                    let processedData = [];
                    s3.listObjectsV2(params, (err, data) => {
                        if (!err) {
                            const contents = data.Contents;
                            const fetch = [];
                            contents.forEach(content => {
                                fetch.push(getObject(content))
                            });
                            Promise.all(fetch).then(data => {
                                data.forEach(d => {
                                    processedData = processedData.concat(d);
                                });
                                qresolve(processedData);
                            });
                        }
                    });
                }));
        });
lousybear
  • 453
  • 3
  • 12