【发布时间】:2016-10-20 14:54:42
【问题描述】:
所以我在纯 node.js 中编写我的 Web 服务器,只使用 bluebird 来代替 promisify。这已经困扰了我一个星期,我无法决定我应该真正使用哪个。我已经阅读了大量关于这两个主题的帖子、博客和文档,请根据您自己的工作经验回答,谢谢。这是详细的总结和相关问题。
这两种方法都已经过测试,它们都非常有效。但是我无法测试性能,我只有自己的基本网站文件(html、css、img、小型数据库等),我从来没有管理过视频文件和大型数据库。
下面是代码部分,给你一些基本的想法(如果你真的知道用哪一个,就不要费心阅读代码,为你节省一些时间),这个问题不是关于逻辑的,所以你可以阅读虚线之间的部分。
关于fs.createReadStream:
优点:适用于大文件,一次读取一个块,节省内存,管道非常智能。
缺点:同步,不能被承诺(流是一个不同的概念来承诺,太难了,不值得)。
//please ignore IP, its just a custom name for prototyping.
IP.read = function (fpath) {
//----------------------------------------------------
let file = fs.createReadStream(fpath);
file.on('error', function () {
return console.log('error on reading: ' + fpath);
});
return file;
//----------------------------------------------------
};
//to set the response of onRequest(request, response) in http.createServer(onRequest).
IP.setResponse = function (fpath) {
let ext = path.extname(fpath),
data = IP.read(fpath);
return function (resp) {
//----------------------------------------------------
//please ignore IP.setHeaders.
resp.writeHead(200, IP.setHeaders(ext));
data.pipe(resp).on('error', function (e) {
cosnole.log('error on piping ' + fpath);
});
//----------------------------------------------------
}
};
关于fs.readFile:
优点:异步,可以很容易地被承诺,这使得代码非常容易编写(开发)和阅读(维护)。还有其他一些我还没接触过的好处,比如数据验证、安全性等。
缺点:不适合大文件。
IP.read = function (fpath) {
//----------------------------------------------------
let file = fs.readFileAsync(fpath);
return file;
//----------------------------------------------------
};
//to set the response of onRequest(request, response) in http.createServer(onRequest).
IP.setResponse = function (fpath) {
const ext = path.extname(fpath);
return function (resp) {
//----------------------------------------------------
IP.read(fpath).then((data) => {
resp.writeHead(200, IP.setHeaders(ext));
resp.end(data);
}).catch((e) => {
console.log('Problem when reading: ' + fpath);
console.log(e);
});
//----------------------------------------------------
}
};
以下是我的选择:
• 简单的方法:使用fs.createReadStream 处理一切。
• 正确方法:仅对大文件使用fs.createReadStream。
• 实用的方法:使用fs.readFile 处理所有问题,直到出现相关问题,然后使用fs.createReadStream 处理这些问题。
我的最终决定是仅将 fs.createReadStream 用于大文件(我将为大文件创建一个函数),并将 fs.readFile 用于其他所有内容。这是一个好的/正确的决定吗?有更好的建议吗?
P.S.(不重要):
我真的很喜欢自己构建基础设施,给你一个想法,当我实例化一个服务器时,我可以像这样设置路由,并自定义我想要的任何东西。请不要建议我使用框架:
let routes = [
{
method: ['GET', 'POST'],
uri: ['/', '/home', '/index.html'],
handleReq: function () {return app.setResp(homeP);}
},
{
method: 'GET',
uri: '/main.css',
handleReq: function () {return app.setResp(maincssP);}
},
{
method: 'GET',
uri: '/test-icon.svg',
handleReq: function () {return app.setResp(svgP);}
},
{
method: 'GET',
uri: '/favicon.ico',
handleReq: function () {return app.setResp(iconP);}
}
];
或者我可以自定义它并将其放入config.json 文件中,如下所示:
{
"routes":[
{
"method": ["GET", "POST"],
"uri": ["/", "/home"],
//I will create a function(handleReq) in my application to handle fpath
"fpath": "./views/index.html"
},
{
"method": "GET",
"uri": "/main.css",
"fpath": "./views/main.css"
},
{
"method": "GET",
"uri": "/test-icon.svg",
"fpath": "./views/test-icon.svg"
}
]
}
【问题讨论】:
-
总是使用
fs.createReadStream()会出现什么问题?它有效,易于使用,内存消耗要好得多,而且流本身不是同步的,因此不会阻塞您的应用。 -
相关:github.com/petkaantonov/bluebird/issues/225 - rl;dr:您无需承诺
createReadStream(),因为它会立即返回。不要“仅仅因为”过度使用承诺。 -
致 robertklep:正如我所说,两种实现都没有问题。感谢您的引用,“流本身不是同步的,因此它不会阻止您的应用程序”,确实已经解决了问题。是的,我会选择简单的方法。
-
致 Tomalak:是的,我几天前读过那篇文章。而且我知道承诺只返回一个结果,与流的行为不同,随着时间的推移会产生结果。感谢您提醒我不要仅仅因为我觉得它很酷而过度使用承诺。
标签: node.js asynchronous stream promise readfile