随手笔记:服务器端渲染 & 浏览器端渲染

前言:本文中提到的“渲染”指的是 render 阶段,即输出 HTML 的过程,而不是浏览器对 HTML 的 paint(绘制)阶段。你可以理解为 HTML = data + template。

目前风头正劲的前端 MVC、MVP、MVVM、Flux 正在围剿传统的 Server-side MVC(比如 Rails、Express 等),而两者均形成了“前后端分离”。

一个阵营是传统 Server-side MVC 的进化,将原本的 Model 交给数据服务器(一般是 Java),将 Controller 、View 、由数据服务器处获得的 伪 Model 交给渲染服务器(一般是 Node),于是前端工程师们掌握了 Web 与 Node ,声称实现了“前后端分离”。

另一个阵营则是各种前端 JS 框架,从数据服务器处获得 Model 交给前端,仅使用数据接口,如 iOS/Android 客户端般与后端完全分离,于是这又是一种“前后端分离”。

明显地,两种方案的渲染方式不同。做了个小实验来看看,顺便记下细节。 至于能发现什么,自己看咯。

以下实验中,所采用到的工具/资源:

  • SUI Mobile
  • 微信公众号测试号
  • Express 框架 + ejs 模板引擎
  • artTemplate 模板引擎

一、服务器端渲染

服务器端( Node.js )源码:

========= C ============

app.get('/', function (req, res) {  
  res.render('index', {
    title: '后端来的',
    list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
  })
})

========= V ============


<!-- 这里是页面内容区 -->  
<div class="content">  
  <% for (var i = 0; i < list.length; i ++) { %>
  <div class="card">
      <div class="card-header"><%= list[i] %></div>
      <div class="card-content">
        <div class="card-content-inner">头和尾的卡片。卡头是用来显示一些额外的信息,或自定义操作卡标题和页脚。</div>
      </div>
      <div class="card-footer"><%= title %></div>
  </div>
  <% } %>
</div>  

服务器端渲染效果:

正常在服务器端渲染

浏览器中查看代码,或是使用爬虫获得响应:

<!-- 这里是页面内容区 -->  
<div class="content">

  <div class="card">
      <div class="card-header">文艺</div>
      <div class="card-content">
        <div class="card-content-inner">头和尾的卡片。卡头是用来显示一些额外的信息,或自定义操作卡标题和页脚。</div>
      </div>
      <div class="card-footer">后端来的</div>
  </div>

  <div class="card">
      <div class="card-header">博客</div>
      <div class="card-content">
        <div class="card-content-inner">头和尾的卡片。卡头是用来显示一些额外的信息,或自定义操作卡标题和页脚。</div>
      </div>
      <div class="card-footer">后端来的</div>
  </div>

  <div class="card">
      <div class="card-header">摄影</div>
      <div class="card-content">
        <div class="card-content-inner">头和尾的卡片。卡头是用来显示一些额外的信息,或自定义操作卡标题和页脚。</div>
      </div>
      <div class="card-footer">后端来的</div>
  </div>

  <div class="card">
      <div class="card-header">电影</div>
      <div class="card-content">
        <div class="card-content-inner">头和尾的卡片。卡头是用来显示一些额外的信息,或自定义操作卡标题和页脚。</div>
      </div>
      <div class="card-footer">后端来的</div>
  </div>

  <div class="card">
      <div class="card-header">民谣</div>
      <div class="card-content">
        <div class="card-content-inner">头和尾的卡片。卡头是用来显示一些额外的信息,或自定义操作卡标题和页脚。</div>
      </div>
      <div class="card-footer">后端来的</div>
  </div>

  <div class="card">
      <div class="card-header">旅行</div>
      <div class="card-content">
        <div class="card-content-inner">头和尾的卡片。卡头是用来显示一些额外的信息,或自定义操作卡标题和页脚。</div>
      </div>
      <div class="card-footer">后端来的</div>
  </div>

  <div class="card">
      <div class="card-header">吉他</div>
      <div class="card-content">
        <div class="card-content-inner">头和尾的卡片。卡头是用来显示一些额外的信息,或自定义操作卡标题和页脚。</div>
      </div>
      <div class="card-footer">后端来的</div>
  </div>

</div>  

二、浏览器端渲染

浏览器端 ( Web ) 源码:

<!-- 这里是页面内容区 -->  
<div class="content" id="here"></div>  
<script id="test" type="text/html">  
<% for (var i = 0; i < list.length; i ++) { %>  
<div class="card">  
    <div class="card-header"><%= list[i] %></div>
    <div class="card-content">
      <div class="card-content-inner">头和尾的卡片。卡头是用来显示一些额外的信息,或自定义操作卡标题和页脚。</div>
    </div>
    <div class="card-footer"><%= title %></div>
</div>  
<% } %>  
</script>

<script>  
var data = {  
    title: '前端来的',
    isAdmin: true,
    list: ['11', '22', '33', '44', '55', '66', '77']
};
var html = template('test', data);  
document.getElementById('here').innerHTML = html;  
</script>  

浏览器端渲染效果:

浏览器端渲染效果

浏览器中查看代码,或是使用爬虫获得响应:

同源码一致:

<!-- 这里是页面内容区 -->  
<div class="content" id="here"></div>  
<script id="test" type="text/html">  
<% for (var i = 0; i < list.length; i ++) { %>  
<div class="card">  
    <div class="card-header"><%= list[i] %></div>
    <div class="card-content">
      <div class="card-content-inner">头和尾的卡片。卡头是用来显示一些额外的信息,或自定义操作卡标题和页脚。</div>
    </div>
    <div class="card-footer"><%= title %></div>
</div>  
<% } %>  
</script>

<script>  
var data = {  
    title: '前端来的',
    isAdmin: true,
    list: ['11', '22', '33', '44', '55', '66', '77']
};
var html = template('test', data);  
document.getElementById('here').innerHTML = html;  
</script>  

三、总结:

  • 由服务器端进行 data 和 template 的取得,生成 HTML 再输出,速度快;
  • 而浏览器渲染,需要取得 template ,然后取得 data ,最后还得进行 JS 的执行来改变内容区域的 DOM。
  • 服务器端渲染方案的一般做法是做成多页应用,页面间的每一次跳转都是一个新的页面,需要重新获取静态资源(虽然有 from cache);
  • 浏览器端渲染方案的一般做法是单页应用(SPA),无刷新跳转,只有一个 HTML 页面,AJAX 与数据接口进行纯数据的通信,依靠 JS 动态地控制 DOM 的变化。
  • 服务器端渲染方案明显是易于 SEO 的;
  • 浏览器端渲染方案在 SEO 上要花大力气却还不容易做得好。

由此可见,服务器端渲染的好处的确是首屏加载快,易于 SEO;浏览器端渲染的好处是:交互体验更好,JS 掌控整个应用。

应该选择哪种方案?

如果是信息展示类网站,选择服务器端渲染方案。(website,例如 http://www.infoq.com/cn/)

如果是重交互的 Web 应用,选择浏览器端渲染方案。(Web app, 例如 https://inbox.google.com/)

最后说说我的常用技术栈吧:

  • 服务器端渲染 express
  • 浏览器端渲染 React + Redux,也用过 Vue
  • 移动原生应用 React Native + Redux
  • 后端云服务 LeanCloud(中国的 Parse),Wilddog(中国的 Firebase)

[完]

Hugo Jing

Shanghai, China https://changshiban.com
温馨提示:以下为赞助商广告,用以维持服务器费用,从而继续创作原创内容,敬请谅解