NodeJSNoob NodeJSNoob - 1 month ago 14
Node.js Question

Node JS Promises then chaining not in order

I'm trying to get my Node JS code to work step by step instead of asynchronously using Promise then.

I first delete all the spreadsheets, then generate them, then zip them, then encrypt the zip, then send the zip via email, then delete the spreadsheets.



//Schedules the job at a specific time
var start = schedule.scheduleJob({
hour: 19,
minute: 26,
dayOfWeek: 3
}, function() {
sendIt();
});

//Starts the Promise Chain
function sendIt() {
return deleteSpreadsheets().then(generateSpeadsheets).then(zipSpreadsheets).then(encrypt).then(sendEmail).then(deleteSpreadsheets);
}

//Deletes the current Spreadsheets in the folder
function deleteSpreadsheets() {
var promise = new Promise(function(resolve, reject) {
console.log('Deleting Spreadsheets');
var locationSpread = ['Location.xlsx'];

locationSpread.forEach(function(filename) {

if (fs.existsSync("./Spreadsheets/" + filename)) {
fs.unlink("./Spreadsheets/" + filename, (err) => {
if (err) {
console.log('Spreadsheet ' + filename + ' not found');
} else {
console.log('Spreadsheet ' + filename + ' successfully deleted');
}
});
}
});
resolve();
});
return promise;
}

//Generates the new Spreadsheets
function generateSpeadsheets() {

var promise = new Promise(function(resolve, reject) {
console.log('Generating Spreadsheets');

var locationSpread = ['Location.xlsx'];

locationSpread.forEach(function(filename) {

var query = connection.query('SELECT * from ' + filename.slice(0, -5), function(err, rows) {

var workbook = excelbuilder.createWorkbook('./Spreadsheets/', filename);
if (workbook == null) {
console.log('workbook null')
};

var sheet = workbook.createSheet(filename.slice(0, -5), 3, rows.length + 1);
if (sheet == null) {
console.log('sheet null')
};
sheet.set(1, 1, 'First Name');
sheet.set(2, 1, 'Last Name');
sheet.set(3, 1, 'Company');

for (var j = 2, z = 0; z < rows.length; j++, z++) {
sheet.set(1, j, rows[z].firstName);
sheet.set(2, j, rows[z].lastName);
sheet.set(3, j, rows[z].company);
}

workbook.save(function(err) {
console.log('workbook saved ' + (err ? 'failed' : 'ok'));
});
});
});
resolve();
});
return promise;
}

//Generates a Zip file with all the Spreadsheets
function zipSpreadsheets() {

var promise = new Promise(function(resolve, reject) {
console.log('Zipping Spreadsheets');
var zipFolder = require('zip-folder');
zipFolder('./Spreadsheets/', './Spreadsheets.zip', function(err) {
if (err) {
console.log('Failed to zip folders', err);
reject();
} else {
console.log('Successfully zipped folder');
}
});
resolve();
});
return promise;
}

//Encrypts the Spreadsheet
function encrypt() {

var promise = new Promise(function(resolve, reject) {
console.log('Encrypting');
spawn = require('child_process').spawn;
zip = spawn('zip', ['-P', 'something', 'Encrypted.zip', './Spreadsheets.zip']);
zip.on('exit', function(code) {
console.log('Finished encrypting');
resolve();
});
});

return promise;
}

//Sends the Encryped Zip as an attached in an email
function sendEmail() {

var promise = new Promise(function(resolve, reject) {
console.log("MAIL SCHEDULE RUNNING");

var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'email', // Your email id
pass: 'password'
}
});

var content = 'something';

var mailOptions = {
from: 'email', // sender address
to: 'email', // list of receivers
subject: 'Title', // Subject line
text: content,
attachments: [{
// file on disk as an attachment
filename: 'Encrypted.zip',
path: './Encrypted.zip' // stream this file
}]
};

transporter.sendMail(mailOptions, function(error, info) {
if (error) {
console.log(error);
reject();
} else {
console.log('Message sent: ' + info.response);
resolve();
};
});
});
return promise;
}





This doesn't seem to be working as planned as seen in the logs:

Deleting Spreadsheets
Generating Spreadsheets
Zipping Spreadsheets
Encrypting
**Spreadsheet Location.xlsx successfully deleted**
**Finished encrypting**
MAIL SCHEDULE RUNNING
**Successfully zipped folder**
**workbook saved ok**
Message sent: -----------------------------------------------
Deleting Spreadsheets
Spreadsheet Location.xlsx successfully deleted


Here's what it should be:

Deleting Spreadsheets
**Spreadsheet Location.xlsx successfully deleted**
Generating Spreadsheets
**workbook saved ok**
Zipping Spreadsheets
**Successfully zipped folder**
Encrypting
**Finished encrypting**
MAIL SCHEDULE RUNNING
Message sent: -----------------------------------------------
Deleting Spreadsheets
Spreadsheet Location.xlsx successfully deleted

Answer Source

You are returning the promise, then resolving in the wrong way. Also you are not waiting for all the deletions to happen. Check this out.

function deleteSingle(filename) {
  return new Promise((resolve, reject) => {
    if (fs.existsSync("./Spreadsheets/" + filename)) {
      fs.unlink("./Spreadsheets/" + filename, (err) => {
        //handle errors or whatever
        return resolve();  
      });
    } else {
      //handle if file doesnt exist
      return resolve();
    }
  })
}

//Deletes the current Spreadsheets in the folder
function deleteSpreadsheets() {
  //we are maping each value inside locationSpread and passing it to the deleteSingle function which returns a promise
  return Promise.all(locationSpread.map(deleteSingle))
}

So, I splitted your code. deleteSingle function returns a promise which resolves once the file is deleted (it also resolves if the file is not deleted or doesnt exist, you modify it to do whatever you want).

Then, the deleteSpreadsheets function returns a single promise, which will be resolved once the array of promises inside resolves. So you can call deleteSpreadsheets().then.... etc