I am reading some .dbf files selected by user and writing that data to an excel file. I am using electron for this purpose. My code is working fine, but it blocks the main thread for a while. Here is my code:
ipcMain.on('create-one-file', (event, reportName, additionalColumns = [], startingRowNo = 5) => {
// show dialog to choose .dbf files that user wants to write in GST report
dialog.showOpenDialog({
filters: [
{ name: 'CSV Files', extensions: ['csv'] }
],
properties: ['openFile', 'multiSelections']
}, (fileNames) => {
if (fileNames) {
event.sender.send('create-one-file-loading-message', 'Reading from template');
// read the template file
XLSX.fromFileAsync(path.join(__dirname, `../sample-files/${reportName}.xlsx`)).then((workbook) => {
let rowIndex = 0;
let count = 0;
// loop through all the files
async.whilst(
() => count < fileNames.length,
callback => { // this function will be called on every iteration
// start parsing dbf file
const parser = new Parser(fileNames[count], { encoding: 'utf-8' });
let worksheet = null;
let noOfColumns = 0;
parser.on('start', () => {
event.sender.send('create-one-file-loading-message', `writing ${path.parse(fileNames[count]).name.toLowerCase()} report`);
// reset row no. as new sheet is being written
rowIndex = 0;
// select the sheet to work on
worksheet = workbook.sheet(path.parse(fileNames[count]).name.toLowerCase());
if (worksheet) {
// get total columns in the worksheet
noOfColumns = (worksheet.row(3) && worksheet.row(3)._node
&& worksheet.row(3)._node.children && worksheet.row(3)._node.children.length
&& worksheet.row(3)._node.children.length - 1) || 0;
}
});
parser.on('record', (record) => {
if (worksheet) {
let cells = [...additionalColumns, ...Object.values(record)];
cells.shift();
cells.shift();
let isNull = true;
cells.forEach((cell, columnIndex) => {
if ((columnIndex + 1) < noOfColumns && cell) {
isNull = false;
}
});
if (!isNull) {
rowIndex = rowIndex + 1;
cells.forEach((cell, columnIndex) => {
if ((columnIndex + 1) < noOfColumns) {
if (!cell || cell === "NaN") cell = "";
worksheet.row(rowIndex + startingRowNo - 1).cell(columnIndex + 1).value(cell);
}
});
}
}
});
parser.on('end', () => {
count++;
callback(null);
});
parser.parse();
},
err => {
if (err) {
event.sender.send('create-one-file-error', err.message, 'Error reading reports');
} else {
event.sender.send('create-one-file-loading-message', 'Finishing it up');
workbook.toFileAsync(`D:/${reportName}.xlsx`).then(() => {
event.sender.send('create-one-file-success', `Successfully created file at D:/${reportName}.xlsx. Click this message to see the file`);
}).catch((error) => {
event.sender.send('create-one-file-error', error.message, `Error writing file. Please make sure that D:/${reportName}.xlsx is closed`);
});
}
}
);
}).catch((err) => {
event.sender.send('create-one-file-error', err.message, 'Error reading template');
});
} else {
event.sender.send('create-one-file-cancelled');
}
});
});
As you can see in the code that after selecting the files I am calling fromFileAsync function which returns a promise. And as far as I know, promises does not block the caller. Then why on my side, the code is blocking my UI, till a new file has been created?