Node.js Web服务器fs.createReadStream vs fs.readFile?
所以我正在写我的web服务器在纯node.js,只使用bluebird
promisify
。 这一直困扰我一个星期,我不能决定我应该使用哪一个。 我已经阅读了大量关于这两个主题的post,博客和文档,请根据您自己的工作经验回答,谢谢。 这里有详细的总结和相关的问题。
两种方法都经过testing,它们都很好。 但是我不能testing性能,我只有自己的基本网站文件(html,css,img,小型数据库等),而且我从来没有pipe理过的video文件和庞大的数据库。
下面是代码部分,给你一些基本的想法(如果你真的知道使用哪一个,不用费心去阅读代码,为了节省一些时间),这个问题不是关于逻辑,所以你可以阅读虚线。
关于fs.createReadStream
:
优点:对于大文件很好,它一次读取一个块,节省内存和pipe道真的很聪明。
缺点:同步,不能被promisified(stream是一个不同的概念承诺,太难做,不值得)。
//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
:
优点:asynchronous,可以很容易地promisified,这使得代码真正的写(开发)和阅读(维护)很容易。 还有其他的好处,我还没有得到,如数据validation,安全等。
缺点:对于大文件不好。
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); }); //---------------------------------------------------- } };
这是我的select:
简单的方法:使用fs.createReadStream
来处理所有事情。
•正确的方法: fs.createReadStream
大文件使用fs.createReadStream
。
实际的方法:使用fs.readFile
处理所有事情,直到出现相关问题,然后使用fs.createReadStream
处理这些问题。
我最后的决定是只使用fs.createReadStream来处理大文件(我将为大文件创build一个函数),而对于其他所有文件则使用fs.readFile。 这是一个好的/适当的决定? 有更好的build议吗?
PS(不重要):
我真的很喜欢自己构build基础架构,给你一个想法,当我实例化一个服务器,我可以像这样设置路由,并自定义任何或我想要的。 请不要build议我使用框架:
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" } ] }
我们来讨论一下实际的实际方法。
您不应该在生产中从Node提供静态文件
createReadStream
和readFile
都非常有用 – 在大多数情况下, createReadStream
更加有效,如果你正在处理大量的文件(而不是服务于它们),那就考虑它。
你应该从静态文件服务器提供静态文件 – 大多数PaaS的networking主机自动为你做这个,如果你自己设置一个环境,你会发现自己反向代理节点,像IIS应该服务于静态文件。
这只对静态文件是真实的,再一次,如果你阅读并转换它们多次你的问题变得非常相关。
为了其他目的,您可以安全地使用fs.readFileAsync
我使用readFile
读取文件到缓冲区并使用它们很多,而createReadStream
可以提高延迟 – 总体而言,您应该获得相似的吞吐量,并且API更易于使用和更高级别。
所以最后
- 如果您正在提供静态文件,则不要从生产中的Node执行。
- 如果您要将文件转换为stream并且延迟非常重要,请使用
createReadStream
。 - 否则,更喜欢
readFile
。