OurJS


OurJS-我们的JS, 我们的技术-IT文摘; 专注JS相关领域;
我们热爱编程, 我们热爱技术;我们是高大上, 有品味的码农;

欢迎您订阅我们的技术周刊


我们会向您分享我们精心收集整理的,最新的行业资讯,技术动态,外文翻译,热点文章;
我们使用第三方邮件列表向您推送,我们不保存您的任何个人资料,注重您的隐私,您可以随时退订,

欢迎分享您的观点,经验,技巧,心得

让我们一起找寻程序员的快乐,探索技术, 发现IT人生的乐趣;


本网站使用缓存技术每次加载仅需很小流量, 可在手机中流畅浏览;
如果您发现任何BUG,请即时告知我们: ourjs(at)ourjs.com

为什么你应该抛弃Express的视图渲染引擎


分享到
分类 大话编程   关键字 Node.JS   发布 pockry  1415249311893
注意 转载须保留原文链接,译文链接,作者译者等信息。  

翻译自StrongLoop Blog, 作者:Patrick Steele-Idem。你也可以到我的博客看本文。

Nodejs Express框架的一个被人们广为使用的特性是它的渲染引擎。Express视图渲染引擎允许Controller提供一个视图名称和视图模型对象给Express,然后返回由HTTP响应流输出的一些字节。基于为eBay的Nodejs技术栈提供支持所获得的经验,我们发现了这个方法的缺点并决定彻底的弃用它。我们这么做了之后,能明显看到页面加载速度的提升、更好的模块性以及开发者生产力的提高。本文将解释为什么你不应该使用Express视图渲染引擎,并提供一个推荐的替代方案。

Express视图渲染引擎

在解释Express视图渲染引擎的缺点之前,让我们先来快速的过一遍它的用法。首先你必须使用类似下面的代码来配置你的Express app:

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

第一行代码告诉Express在views目录下搜索所有模板,第二行则在这些模板上应用jade模板引擎。

配置好之后,你能在Controller中使用res.render(viewName, viewModel)方法来渲染视图,代码如下:

app.get('/', function (req, res) {
  res.render('index', { title: 'Hey', message: 'Hello there!'});
})

这里面的机制是,Express将视图名称对应到模板文件的路径,使用关联的模板引擎来渲染模板,将结果输出到response,最后结束响应。

不好的地方

这个方法看起来如此简单,你可能从来没想过它会出错。但实际上它还是有不少问题,当出问题时会影响web程序性能和可维护性,下面我们讲到这些。

破坏模块性

Express强制性的要求设置一个views目录,所有模板都堆放在这里。本来你可以将模板放到Controller或使用这些模板的UI组件附近,现在你不得不将它们放到一个单独的顶级目录里。一个典型的基于Express的项目,它的目录结构将会与下面类似:

    routes/
        home.js
        login.js
        …
    views/
        home.jade
        login.jade
        …

使用Express推荐的目录结构,你不得不将源码按照类型而非特性来分来。作为结果,紧密相关的文件将被分离到截然不同的目录树里面,这意味着如果你需要修改一个功能,你可能需要遍历整个项目的目录以修改不同的文件。在后面的替代方案里我会介绍一个更健康的、模块化的目录结构。

与Express高度耦合

当使用Express视图渲染引擎,意味着你在使用一个与Express高度耦合的特性。如果你想在客户端渲染一个模板呢?如何解析局部模板?如果你想切换到另一个web框架或者不使用框架呢?事实是,Express引入的这个解析和渲染模板的新方法,只能在服务端并且只能在Express中使用。当构建同构(isomorphic)web app时,我们希望在服务端和客户端使用更一致的渲染模板的方法。

没有Streaming

Express视图渲染引擎不支持streaming(流式传输),这对于客户端和服务端两方的性能都有负面影响。在服务端,当渲染一个HTML页面模板时,整个HTML输出都被当做一个超长的字符串存储在内存里,当整个HTML输出都构造完成之后,才开始向HTML响应里输出第一个字节。这是因为所有的视图引擎都必须使用回调来实现。而只有当整个HTML都被渲染完毕,回调才会被调用。不使用streaming来输出HTML,我们将浪费服务端的内存,以及增加客户端等待响应的时间。

使用streaming来传输响应的好处还包括,更早的发送页面的<head>部分,因此客户端能够更快的下载页面的CSS文件。为了感受streaming带来的好处,你需要使用支持streaming的模板引擎。此外,支持异步渲染的模板引擎(如MarkoDustNunjucks)甚至能够在视图模型构造完成之前就输出响应,因此能带来更多的性能提升。

集中式的配置

并不是所有的配置都不好,但不必要的配置是不好的。如果应用不同的地方需要不用的配置,集中式的配置将引起冲突。比如,如果需要多个view目录呢?Express的sub-apps能在一定程度上解决这个问题,但最好的办法的还是避免额外的配置。

解决办法

Express将它自己描述为一个框架,那么绕过Express视图渲染引擎实际上还是很容易的。这将让开发者创造更灵活的、易理解的和更高性的应用。首先你必须理解一个重要的概念,res对象实际上是一个可写的HTTP响应流(尽管它已经被Express重度修改过),因此你能够直接向响应里输出:

app.get('/', function (req, res) {
    res.write('Hello Frank');
    res.end();
});

如果你想渲染一个jade模板到HTTP响应,你可以照下面做:

var templatePath = require.resolve('./template.jade');
var templateFn = require('jade').compileFile(templatePath);

app.get('/', function (req, res) {
    res.write(templateFn({name: 'Frank'});
    res.end();
});

这个方法比起res.render()有些啰嗦,但它很直观也更灵活。

注意:你可能注意到我们使用了require.resolve来获得模板的绝对路径,这个模板和我们的Controller模块放在一起。

如果你的模板引擎支持输出到一个流,代码将会更简单。比如Marko模板引擎的代码如下:

var templatePath = require.resolve('./template.marko');
var template = require('marko').load(templatePath);

app.get('/', function (req, res) {
    template.render({name: 'Frank'}, res);
});

视图解析程序

如果你觉得你的app需要使用视图解析程序(比如你需要为A/B测试使用不同的模板,或者根据用户的地区来确定模板),也有一个非常干净的解决办法。下面的代码假想了一个独立于Express的视图解析程序,它是如何根据名称和一些上下文(本例中是请求和当前目录)来解析视图模板的。

var myViewResolver = require('my-view-resolver');

app.get('/', function (req, res) {
    var template = myViewResolver.resolve('hello', req, __dirname);
    template.render({name: 'Frank'}, res);
});

使用一个明确的视图解析程序能让代码更容易理解,并提供更高的灵活度。

项目结构

现在你可以不受只能有一个views目录的限制了。让我们来看看新的项目结构:

    pages/
        home/
            index.js
            style.css
            template.marko
        login/
            index.js
            style.css
            template.marko

新的项目结构让关联的文件放在相同的目录,从此之后可以模块化的开发和维护项目了。

总结

尽管Express是一个极简主义的框架,但也没有必要一定要使用它所有的特性。有些时候独立的模块能比它做得更好。Nodejs其中的一条指导原则就是“模块应该只做一件事并把它做好”,并且我认为Express将诸如视图渲染和路由这些特性分离开来会更好。我们已经看到Express 4.x里分离了不少核心的中间件,我认为还应该更进一步。也许我们根本不需要一个框架。也许我们只需要一些在一起工作良好的模块就行。

希望现在你对于绕过Express视图渲染的好处已经明了于心了,如果你想看看具体的示例,可以看这里的示例程序。这里还有更大型的天气示例应用可供参考,希望能对你有所帮助。

原文地址: 点此
社区评论 ( Beta版 )
OnceDoc 您自己的企业内容管理系统——文档、流程、知识库、报表、网盘All In One

访问404页面,寻找丢失儿童
 热门文章 - 分享最多
  1. node.js使用unzip解压zip包指定文件,提取 word/excel (docx/pptx/xlsx) 文本内容
  2. Linux下用node.js提取Word(doc/docx)/PDF文本内容
  3. 好与坏的程序员
  4. 2017 开发者报告:Java最流行的语言,JavaScript最常用的语言,Go最有前途的语言
  5. 小程序排名高低,关键还是看这些因素!
  6. 正则中test、exec、match的简单区别,以及括号的用法
  7. AirJD-简单好用的免费建站工具

 相关阅读 - 大话编程
  1. 好与坏的程序员
  2. Node.JS通过读取PATH环境变量获取可执行文件的安装地址
  3. 程序员年纪大就做不了了?这些45到60岁的码农还在写代码
  4. 国家卫计委发文要求互联网医院全部注销
  5. linux用tar文件压缩命令备份系统的方法
  6. JavaScript使用ES6的Class面向对象继承时 this is not defined 解决方法
  7. TCP/UDP协议比较:在Node.JS中UDP服务器和客户端通信示例
  8. 周鸿祎:一些程序员没有商业意识,却又很自负,一看就知道不会创业
  9. 微信抢红包插件示例代码及其实现原理
  10. 学哪种语言的最赚钱?调查显示JavaScript和SQL是程序员最常用的语言

 关键字 - Node.JS
  1. 6款基于Node.JS的开源内容管理和静态网站生成系统
  2. 在nodejs中使用Redis缓存和查询数据及Session持久化(Express)
  3. Node.JS中如何判断递归嵌套的所有回调函数已经执行完毕,以读取目录下所有文件为例:计数比Promise方式快将近一倍
  4. Node.js网页抓取:一个最简单的http请求客户端示例(request client)
  5. 为什么你应该抛弃Express的视图渲染引擎
  6. 用纯Node.JS弹出Windows系统消息提示框(MessageBox)
  7. 理解Node.js的事件循环(Event Loop)和线程池
  8. Node.JS中如何快速扫描端口并发现局域网内的Web服务器地址(80)
  9. Express入门教程:一个简单的博客
  10. Node.JS循环递归复制文件夹目录及其子文件夹下的所有文件

 欢迎订阅 - 技术周刊

我们热爱编程, 我们热爱技术; 我们是高端, 大气, 上档次, 有品味, 时刻需要和国际接轨的码农; 欢迎您订阅我们的技术周刊; 您只需要在右上角输入您的邮箱即可; 我们注重您的隐私,您可以随时退订.
加入我们吧! 让我们一起找寻码农的快乐,探索技术, 发现IT人生的乐趣;


 关注我们

我们的微信公众号: ourjs-com
打开微信扫一扫即可关注我们:
IT文摘-程序员(码农)技术周刊

ourjs官方微信号