Learn, Share, Build

202
September 19, 2017, at 1:28 PM

I have this code that serves every markdown file in the './markdown' folder. At '/api/markdown/filename'.

var apiRouter = express.Router();
markdownFolder = './markdown/';
apiRouter.get('/:markdown_file_noext', function(req, res) {
        fs.readdir(markdownFolder, function(err, markdown) {
            if (err) throw err;
            markdown.forEach(function(file) {
            fs.readFile(markdownFolder + file, 'utf8', function(err, file_content) {
                if (err) throw err;
                fileNoExtension = file.slice(0, file.indexOf('.'));
                if (req.params.markdown_file_noext == fileNoExtension) {
                    res.json({ 
                        'title': fileNoExtension,
                        'markdown': marked(file_content)
                    });
                };
            });
        });
    });
});

But i end having a ton of callbacks do the the nature of the 'fs' methods. How do i avoid this?

Answer 1

Using Q as promise library:

const Q = require('q');
const fs = require('fs');
const markdownFolder = './markdown/';
const readdir = Q.nfbind(fs.readdir);
const readFile = Q.nfbind(fs.readFile);
readdir(markdownFolder).then(markdown => {
    const promises = [];
    markdown.forEach(file => promises.push(readFile(markdownFolder + file, 'utf8')));
    return Q.all(promises);
}).then(files => {
    // Do your magic.
}).catch(error => {
    // Do something with error.
});
Answer 2

You have different option.

  1. Use named Function instead of anonymus functinos. It would make it a little bit more readable but you will still be using callbacks.
  2. Use Promises, but you will need to use bluebird to wrap the fs module.
  3. For a more advance option, you can use generators and Promises to make your code look more like a sync way. Take a look at co or bluebird.coroutine.
Answer 3

With Promises you could do like this:

const path = require('path');
var apiRouter = express.Router();
markdownFolder = './markdown/';
apiRouter.get('/:markdown_file_noext', function(req, res) {
    readdir(markdownFolder)
    .then((files) => {
        const tasks = files.map((file) => {
            const filePath = path.resolve(markdownFolder, file);
            return readFile(filePath);
        });
        return Promise.all(tasks); // Read all files
    })
    .then((fileContents) => {
        return fileContents.map((content) => {
            fileNoExtension = file.slice(0, file.indexOf('.'));
            if (req.params.markdown_file_noext == fileNoExtension) {
                return { 
                    'title': fileNoExtension,
                    'markdown': marked(content)
                };
            };
        })        
    })
    .then((results) => {
        // It's better if you aggregate all results in one array and return it, 
        // instead of calling res.json for each result
        res.json(results);
    })
    .catch((err) => {
        // All errors are catched here
        console.log(err);
    })
});

function readdir(folderPath) {
    return new Promise((resolve, reject) => {
        fs.readdir(folderPath, (err, files) {
            if (err) {
                return reject(err);
            }
            resolve(files);
        });
    });
}
function readFile(filePath) {
    return new Promise((resolve, reject) => {
        fs.readFile(filePath, 'utf8', (err, file_content) => {
            if (err) {
                return reject(err);
            }            
            resolve(file_content);
        });
    });
}
READ ALSO
Learn, Share, Build

Learn, Share, Build

How can i upload images / files to google cloud bucket using angular2/4Is it a must i use Nodejs and express to get the task done

229
Learn, Share, Build

Learn, Share, Build

For anything I try install with npm it returns the same error: Cannot find fstream moduleThe funny thing is that 'fstream' is into my NodeJS folder (C:/Program Files/nodejs/node_modules/npm/node_modules)

218
Learn, Share, Build

Learn, Share, Build

I am using a jquery method to load JSON objects from the databaseThen, I would want to display the record row by row in a HTML table

247
Learn, Share, Build

Learn, Share, Build

wp-admin login page blank validationWhen an admin does not input anything in the wp-admin login page @ time give the error like a please fill up input field

230