启动时用同步代码加载数据到内存可以吗?

Is it okay to use synchronous code to load data into the memory at startup?

在我的 routes.js 文件中,我有这个:

var pages = require('./pages')();
...
app.get('/:page', function(req, res, next) {
    var p = req.params.page;
    if (p in pages) {
        res.render('page', pages[p]);
    } else {
        next();
    }
});

pages.js:

module.exports = function() {
    var fs = require('fs'),
        ret = [],
        dir = './pages',
        files = fs.readdirSync(dir);
    files.forEach(function(file) {
        var text = fs.readFileSync(dir + '/' + file, 'utf-8'),
            fileName = file.substr(0, file.lastIndexOf('.'));
        ret[fileName] = {content: text};
    });
    return ret;
};

这段代码运行只有一个,当我运行节点。这就是我如何让它异步:

require('./pages')(function(pages) {
    app.get('/:page', function(req, res, next) {
        var p = req.params.page;
        if (p in pages) {
            res.render('page', pages[p]);
        } else {
            next();
        }
    });
});

pages.js:

module.exports = function(callback) {
    var fs = require('fs'),
        ret = [],
        dir = './pages';
    fs.readdir(dir, function(err, files) {
        if (err) throw err;
        files.forEach(function(file, i) {
            fs.readFile(dir + '/' + file, 'utf-8', function(err, text) {
                if (err) throw err;
                var fileName = file.substr(0, file.lastIndexOf('.'));
                ret[fileName] = {content: text};
                if ( i === (files.length - 1) ) callback(ret);
            });
        });
    });
};

假设总页面大小不超过 1 MB,我可以将文本无限期地缓存到内存中,而不会因内存不足而导致节点崩溃。

  1. 我应该使用异步代码吗?

    据我了解,异步版本将使节点更快地开始侦听本地主机,但 /:page URL 仅在文件加载到内存中后才有效。

  2. 异步代码的模式是否正确?

  3. 如果我需要在另一个文件中重用 pages 对象怎么办?现在它只能在 routes.js.

    中访问

我可以像这样重写 pages.js 只执行一次吗:

var ret = [];
module.exports = function(callback) {
    var fs = require('fs'),
        dir = './pages';
    if (ret.length < 1) {
        fs.readdir(dir, function(err, files) {
            if (err) throw err;
            files.forEach(function(file) {
                fs.readFile(dir + '/' + file, 'utf-8', function(err, text) {
                    if (err) throw err;
                    var fileName = file.substr(0, file.lastIndexOf('.'));
                    ret[fileName] = {content: text};
                    if ( i === (files.length - 1) ) callback(ret);
                });
            });
        });    
    } else {
        callback(ret);
    }
};
  1. 如果require('./pages')(function(pages) {})一起调用多次怎么办? if 条件是否有可能失败?我无法解决这个问题。

Should I be using the async code?

如果你想要,为什么不呢。但其实并没有这个必要,启动时同步IO就可以了。 require 也是如此。

Is the async code in the right pattern?

没有。它确实为每个目录调用一次 callback。多次调用 app.get('/:page', …) 不是你想要的。

What if I need to reuse the pages object in another file? Right now it is only accessible in routes.js.

您可以将它从 routes.js 传递到其他模块。或者只是重写 pages.js 以静态存储它并仅执行一次异步操作,以便您可以多次要求它。

What if require('./pages')(function(pages) {}) is called multiple times together? Is there a chance of the if condition failing?

是的,它肯定会失败,因为您只是异步填充 ret

I can't wrap my mind around this.

使用承诺。充当异步的、不可变的值,正是您在这里所需要的。他们将保证回调仅被调用一次,每个回调都使用相同的 ret 值调用,并提供更多有用的东西(比如为您管理并行文件读取)。

您需要从 pages.js 导出承诺。