避免回调地狱

时间:2016-12-22 18:30:35

标签: node.js express asynchronous

我有这个代码为' ./ markdown'中的每个降价文件提供服务。夹。在' / 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)
                    });
                };
            });
        });
    });
});

但是,我结束了大量的回调,以及“fs”的性质。方法。我该如何避免这种情况?

3 个答案:

答案 0 :(得分:1)

使用Q作为承诺库:

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.
});

答案 1 :(得分:0)

你有不同的选择。

  1. 使用命名函数代替anonymus functinos。它会使它更具可读性,但你仍然会使用回调。
  2. 使用bluebird,但您需要使用fs来包装co模块。
  3. 对于更高级的选项,您可以使用生成器和Promises使您的代码看起来更像是同步方式。请查看bluebird.coroutine或{{1}}。

答案 2 :(得分:0)

使用Promise你可以这样做:

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);
        });
    });
}
相关问题