Node.js Web 服务器 fs.createReadStream 与 fs.readFile?

标签 node.js asynchronous stream promise readfile

所以我用纯node.js编写我的网络服务器,仅使用bluebird作为promisify。这已经困扰我一周了,我无法决定我应该真正使用哪一个。我已经阅读了大量关于这两个主题的帖子、博客和文档,请根据您自己的工作经验回答,谢谢。这是详细的总结和相关问题。

两种方法都经过测试,效果都很好。但我无法测试性能,我只有自己的基本网站文件(html、css、img、小数据库等),并且从来没有管理过视频文件和庞大的数据库。

下面是代码部分,给你基本的想法(如果你真的知道该使用哪一个,就不用费心阅读代码了,可以节省你一些时间),这道题不涉及逻辑,所以你可以阅读虚线之间的部分。

关于fs.createReadStream:
优点:适用于大文件,一次读取一个 block ,节省内存,而且管道非常智能。
缺点:同步,无法 promise (流是一个不同的概念,很难做到,不值得)。

//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:
优点:异步,很容易被 promise ,这使得代码非常容易编写(开发)和阅读(维护)。还有其他我还没有接触过的好处,比如数据验证、安全性等。
缺点:不适合大文件。

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 。这是一个好的/正确的决定吗?还有更好的建议吗?

附注(不重要):
我真的很喜欢自己构建基础设施,给你一个想法,当我实例化服务器时,我可以像这样设置路由,并自定义我想要的任何内容。请不要建议我使用框架:

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.js 提供静态文件

createReadStreamreadFile 都非常有用 - createReadStream 在大多数情况下更高效,如果您正在处理大量数据,请考虑使用它文件(而不是提供它们)。

无论如何,您都应该从静态文件服务器提供静态文件 - 大多数 PaaS Web 主机会自动为您执行此操作,并且如果您 set up an environment yourself你会发现自己的反向代理 Node 无论如何都位于像 IIS 这样应该提供静态文件的东西后面。

这只适用于静态文件,同样,如果您阅读它们并多次转换它们,您的问题就会变得非常相关。

出于其他目的,您可以安全地使用fs.readFileAsync

我经常使用 readFile 将文件读取到缓冲区并使用它们,而 createReadStream 可以改善延迟 - 总体而言,您应该获得类似的吞吐量,并且 API 更容易使用与更高水平的合作。

结论

  • 如果您提供静态文件并关心性能 - 无论如何不要在生产环境中通过 Node.js 执行此操作。
  • 如果您要将文件转换为流,并且延迟很重要,请使用 createReadStream
  • 否则更喜欢readFile

关于Node.js Web 服务器 fs.createReadStream 与 fs.readFile?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37904093/

相关文章:

node.js - 使用 Node.JS

Node.js 事件代理

javascript - 当promise解析时如何重新渲染React组件? |如何阻止渲染直到数据加载?

javascript - node.js 解析 promise 并返回值

bash - 使用 mkfifo 和传输流,这可能吗?

javascript - 将 typescript 库捆绑到一个 .js 文件和一个 .d.ts

asynchronous - go中如何实现异步读取?

mysql - 使用 mysql 和 node.js 更新 foreach 外部的变量值

c - 从流中读取时大小不同的数组

java - 如何使Spring Controller 在所有请求主体传输之前被调用(并将主体作为流处理)?