启动时用同步代码加载数据到内存可以吗?
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,我可以将文本无限期地缓存到内存中,而不会因内存不足而导致节点崩溃。
我应该使用异步代码吗?
据我了解,异步版本将使节点更快地开始侦听本地主机,但 /:page
URL 仅在文件加载到内存中后才有效。
异步代码的模式是否正确?
如果我需要在另一个文件中重用 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);
}
};
- 如果
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
导出承诺。
在我的 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,我可以将文本无限期地缓存到内存中,而不会因内存不足而导致节点崩溃。
我应该使用异步代码吗?
据我了解,异步版本将使节点更快地开始侦听本地主机,但
/:page
URL 仅在文件加载到内存中后才有效。异步代码的模式是否正确?
如果我需要在另一个文件中重用
中访问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);
}
};
- 如果
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
导出承诺。