drake1994
drake1994

Reputation: 99

Calling a async function with await inside worksheet.eachRow() in exceljs package

const Excel = require("exceljs");
const fs = require("fs");
const createConnection = require("./db.connection");
const SEGMENT = require("./models/segment");

const fileName = "test.xlsx";

createConnection(); //Db connection

const readExcel = async () => {
  try {
    let workbook = new Excel.Workbook();

    await workbook.xlsx.readFile(fileName);

    readRows(workbook);
  } catch (error) {
    console.log("error", error);
  }
};

readExcel();

readRows = (workbook, headers) => {
  workbook.eachSheet((worksheet, sheetId) => {
    // console.log(worksheet);

    worksheet.eachRow({ includeEmpty: false }, async (row, rowNumber) => {
      console.log("Entered ROW at LOC 116", rowNumber);
      const segment = new SEGMENT({ versionName: row.getCell(1).text.trim() });
      const saveSegment = await segment.save(); //Insert into db
      console.log("Entered ROW at LOC 119 Save Segment", saveSegment); //Further code after this line
    });
  });
};

I just want to wait till document is saved in db before doing further processing inside workbook.eachRow loop. The output I am getting is

Entered ROW at LOC 116 1
Entered ROW at LOC 116 2
Entered ROW at LOC 116 3
Entered ROW at LOC 116 4
Entered ROW at LOC 116 5
Entered ROW at LOC 116 6
Entered ROW at LOC 116 7
Entered ROW at LOC 116 8
Entered ROW at LOC 116 9
Entered ROW at LOC 116 10
Entered ROW at LOC 116 11
Entered ROW at LOC 116 12
Entered ROW at LOC 116 13
Entered ROW at LOC 116 14
Entered ROW at LOC 116 15
Entered ROW at LOC 116 16
Entered ROW at LOC 116 17
Entered ROW at LOC 116 18
Entered ROW at LOC 116 19
Entered ROW at LOC 116 20
Entered ROW at LOC 116 21
Entered ROW at LOC 116 22
Entered ROW at LOC 116 23
Entered ROW at LOC 116 24
Entered ROW at LOC 116 25
Entered ROW at LOC 116 26
Entered ROW at LOC 116 27
Entered ROW at LOC 116 28
Entered ROW at LOC 116 29
Entered ROW at LOC 116 30
Entered ROW at LOC 116 31
Entered ROW at LOC 116 32
Entered ROW at LOC 116 33
Entered ROW at LOC 116 34
Entered ROW at LOC 119 Save Segment {
  isDeleted: false,
  isActive: true,
  _id: 62d714775d9c0d736f0d2f92,
  versionName: 'versionName',
  createdAt: 2022-07-19T20:30:47.583Z,
  updatedAt: 2022-07-19T20:30:47.583Z
}
Entered ROW at LOC 119 Save Segment {
  isDeleted: false,
  isActive: true,
  _id: 62d714775d9c0d736f0d2f93,
  versionName: 'versionName',
  createdAt: 2022-07-19T20:30:47.583Z,
  updatedAt: 2022-07-19T20:30:47.583Z
}

which means that each row is getting executed till before I am calling await inside loop. While what I want is entire processing for each row should be completed before moving to second row since workbook.eachrow is a synchronous function. Basicalling output should be like this.

Entered ROW at LOC 116 1
Entered ROW at LOC 119 Save Segment {
  isDeleted: false,
  isActive: true,
  _id: 62d714775d9c0d736f0d2f92,
  versionName: 'versionName',
  createdAt: 2022-07-19T20:30:47.583Z,
  updatedAt: 2022-07-19T20:30:47.583Z
}
Entered ROW at LOC 116 2
Entered ROW at LOC 119 Save Segment {
  isDeleted: false,
  isActive: true,
  _id: 62d714775d9c0d736f0d2f93,
  versionName: 'versionName',
  createdAt: 2022-07-19T20:30:47.583Z,
  updatedAt: 2022-07-19T20:30:47.583Z
}

Is this the same issue that we have while using async/await inside forEach loops?Is there a workaround for it?

Upvotes: 2

Views: 2877

Answers (2)

Ievgen
Ievgen

Reputation: 4443

You can use await Promise.all(promises) to wait for all rows to be properly proccesed.

const someAsyncFn = async(value) => {
  console.log('executing: ' + value);
  return value;
};

var promises = [];
// same as worksheet.eachRow
[1, 2, 3, 4].forEach(p => {
  promises.push(someAsyncFn(p).then(p => {
    console.log('finished call:' + p);
  }));
});

Promise.all(promises).then(p => console.log('all rows are finished'));

Upvotes: 0

One way you can achieve it is to use for loop:

for (let i = 1; i <= worksheet.rowCount; i++) {
  const row = worksheet.getRow(i)
}

Another way could be wrapping eachRow call with a promise:

await new Promise((resolve) => {
  worksheet.eachRow(async (row, i) => {
    const result = await someAsyncFn()

    if (i === worksheet.rowCount) {
      resolve()
    }
  })
}

Upvotes: 5

Related Questions