3
\$\begingroup\$

I just created my first ES6 module in Node, and first time using promises and I was hoping to get some feedback on it. I am the only developer at my current company, so I cannot get feedback here. I just want to make sure whoever comes behind me in the future can have a clean code base to work in.

'use strict';
var fs = require('fs');
var nodeSchedule = require('node-schedule');
class CronJob {
 constructor(filePath, time, rule) {
 this.filePath = filePath;
 this.maxPdfAge = time || 86400000;
 this.currentDate = Date.parse(new Date());
 this.scheduleRule = rule || this.getDefaultRule();
 }
 schedule(callback) {
 nodeSchedule.scheduleJob(this.scheduleRule, err => {
 if (err) return callback(err);
 this.scanFolder((err, info) => {
 if (err) return callback(err, null);
 return callback(null, info);
 });
 });
 }
 scanFolder(callback) {
 scanDirectory(this.filePath)
 .then(files => {
 this.findOldPdfs(this.filePath, files, (err, info) => {
 if (err) return callback(err, null);
 return callback(null, info);
 });
 }).catch(err => {
 callback(err, null);
 });
 }
 findOldPdfs(filePath, pdfs, callback) {
 var pdfDates = getPdfCreateDates(filePath, pdfs);
 Promise.all(pdfDates)
 .then(pdfs => {
 this.deletePdfs(pdfs, (err, info) => {
 if (err) return callback(err, null);
 return callback(null, info);
 });
 })
 .catch(err => {
 callback(err, null);
 });
 }
 deletePdfs(pdfObjects, callback) {
 var pdfsToDelete = getPdfsToDelete(pdfObjects, this.currentDate, this.maxPdfAge);
 Promise.all(pdfsToDelete)
 .then(successMsgs => {
 callback(null, successMsgs);
 }).catch(err => {
 callback(err, null);
 });
 }
 getDefaultRule() {
 var rule = new nodeSchedule.RecurrenceRule();
 rule.dayOfWeek = [0, new nodeSchedule.Range(0, 6)];
 rule.hour = 23;
 rule.minute = 59;
 rule.second = 0;
 return rule;
 }
}
/********************************************/
// Promise function wrappers
/********************************************/
function scanDirectory(filePath) {
 return new Promise((resolve, reject) => {
 fs.readdir(filePath, (err, data) => {
 if (err) {
 reject(err);
 } else {
 resolve(data);
 }
 });
 });
}
function getPdfCreateDates(filePath, files) {
 var arrayOfPromises = [];
 files.forEach(file => {
 var pdfFile = filePath + '/' + file;
 var statLookupPromise = new Promise((resolve, reject) => {
 fs.stat(pdfFile, (err, info) => {
 if (err) {
 reject(err);
 } else {
 resolve({ filePath: pdfFile, dateTime: info.mtime });
 }
 });
 });
 arrayOfPromises.push(statLookupPromise);
 });
 return arrayOfPromises;
}
function getPdfsToDelete(pdfs, currentDate, maxPdfAge) {
 var arrayOfPdfPromises = [];
 pdfs.forEach(pdf => {
 if (currentDate - maxPdfAge > pdf.dateTime) {
 var deletePdfPromise = new Promise((resolve, reject) => {
 fs.unlink(pdf.filePath, (err) => {
 if (err) {
 reject(err);
 } else {
 resolve(pdf.filePath + ' was deleted');
 }
 });
 });
 arrayOfPdfPromises.push(deletePdfPromise);
 }
 });
 return arrayOfPdfPromises;
}
module.exports = CronJob;
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Mar 31, 2017 at 15:39
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$
  1. Watch your names:
    • CronJob - seems too general to me. It's just to do with deleting old pdfs right?
    • findOldPdfs - this one calls deletePdfs, so a better name might be deleteOldPdfs
    • scanFolder - this one also ends up deleting pdfs, so maybe deleteOldFilesInFolder
    • schedule - same here, ends up deleting pdfs. If your class name was something like OldPdfRemover/PdfCleaner/etc it would make more sense.

Think about how this will be called:

cronJob->schedule();
vs
pdfCleaner->schedule();
  1. Consider splitting this into two classes. One to do with cron jobs, and one to do with deleting pdfs.
  2. Consider injecting currentDate. The code is hard to test when there is a variable in there which is changing all the time.
  3. Why keep callback interfaces to your methods? You can return promises directly, and get rid of all of these:

    .then(successMsgs => { callback(null, successMsgs); }).catch(err => { callback(err, null); });

  4. Consider naming your "private" methods with an underscore (ex. _deletePdfs) to make it clear that these are not to be called from the outside

  5. Consider using a more general promise adapter for callbacks. You don't need to write this code more than once. Either write your own, or check out denodify. The words "new Promise" should be a rare sight in your code base.
answered Apr 9, 2017 at 22:55
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.