首先從一個重要的概念「模板」提及。 廣義上來講,web中的模板就是填充數據後能夠生成文件的頁面。 嚴格意義上來講,應該是模板引擎利用特定格式的文件和所提供的數據編譯生成頁面。模板大體分爲前端模板(如ejs)和後端模板(如freemarker)分別在瀏覽器端和服務器端編譯。javascript
所謂的前端渲染就是當咱們去http請求的時候,咱們先去請求到的是模版文件,隨後數據纔會過來,後端渲染是後端模板和數據結合好了之後整個的傳給瀏覽器css
提及模板渲染,樓主首先接觸的其實並非前端模板引擎,而是後端。後端 MVC 模式中,通常從 Model 層中讀取數據,而後將數據傳到 View 層渲染(渲染成 HTML 文件),而 View 層,通常都會用到模板引擎,好比樓主項目中用到的 PHP 的 smarty 模板引擎。隨便上段代碼感覺一下。前端
<div> <ul class="well nav nav-list" style="height:95%;"> {{foreach from=$pageArray.result item=leftMenu key=key name=leftMenu}} <li class="nav-header">{{$key}}</li> {{foreach from=$leftMenu key=key2 item=item2}} <li><a target="main" href='{{$item2}}'>{{$key2}}</a></li> {{/foreach}} {{/foreach}} </ul> </div>
傳入 View 層的其實就是個叫作 $pageArray 的 JSON 數據。而 MVC 模式也是很是容易理解,而後再看看下面這張圖。java
之前的 WEB 項目大多會採用這種後臺 MVC 模式,這樣作有利於 SEO,而且與前端請求接口的方式相比,少了個 HTTP 請求,理論上加載速度可能會稍微快些。可是缺點也很是明顯,前端寫完靜態頁面,要讓後臺去「套模板」,每次前端稍有改動,後臺對應的模板頁面同時也須要改動,很是麻煩。頁面中若是有複雜的 JS,前端寫仍是後端寫?前端寫的話,沒有大量的數據,調試不方便,後端寫的話... 因此樓主看到的 PHPer 一般都會 JS。web
AJAX 的出現使得先後端分離成爲可能。後端專一於業務邏輯,給前端提供接口,而前端經過 AJAX 的方式向後端請求數據,而後動態渲染頁面。後端
咱們假設接口數據以下:瀏覽器
[{name: "apple"}, {name: "orange"}, {name: "peach"}]
假設渲染後的頁面以下:服務器
<div> <ul class="list"> <li>apple</li> <li>orange</li> <li class="last-item">peach</li> </ul> </div>
前端模板引擎出現以前,咱們通常會這麼作:app
<div></div> <script> // 假設接口數據 var data = [{name: "apple"}, {name: "orange"}, {name: "peach"}]; var str = ""; str += '<ul class="list">'; for (var i = 0, len = data.length; i < len; i++) { if (i !== len - 1) str += "<li>" + data[i].name + "</li>"; else str += '<li class="last-item">' + data[i].name + "</li>"; } str += "</ul>"; document.querySelector("div").innerHTML = str; </script>
其實樓主我的也常常這麼幹,看上去簡單方便,可是這樣作顯然有缺點,將 HTML 代碼(View 層)和 JS 代碼(Controller 層)混雜在了一塊兒,UI 與邏輯代碼混雜在一塊兒,閱讀起來會很是吃力。一旦業務複雜起來,或者多人維護的狀況下,幾乎會失控。並且若是須要拼接的 HTML 代碼裏有不少引號的話(好比有大量的 href 屬性,src 屬性),那麼就很是容易出錯了(這樣幹過的應該深有體會)。前後端分離
這個時候,前端模板引擎出現了,Underscore 的 _.template 多是最簡單的前端模板引擎了(可能還上升不到引擎的高度,或者說就是個前端模板函數)。咱們先不談 _.template 的實現,將以上的代碼用其改寫。
<div></div> <script src="//cdn.bootcss.com/underscore.js/1.8.3/underscore.js"></script> <script type="text/template" id="tpl"> <ul class="list"> <%_.each(obj, function(e, i, a){%> <% if (i === a.length - 1) %> <li class="last-item"><%=e.name%></li> <% else %> <li><%=e.name%></li> <%})%> </ul> </script> <script> // 模擬數據 var data = [{name: "apple"}, {name: "orange"}, {name: "peach"}]; var compiled = _.template(document.getElementById("tpl").innerHTML); var str = compiled(data); document.querySelector("div").innerHTML = str; </script>
這樣一來,若是前端須要改 HTML 代碼,只須要改模板便可。這樣作的優勢很明顯,前端 UI 和邏輯代碼再也不混雜,閱讀體驗良好,改動起來也方便了許多。
先後端分離最大的缺點可能就是 SEO 無力了,畢竟爬蟲只會抓取 HTML 代碼,不會去渲染 JS。(PS:如今的 Google 爬蟲已經能夠抓取 AJAX 了 Making AJAX applications crawlable ,具體效果未知)
單純的後端模板引擎(後端 MVC)以及前端模板引擎方式都有必定的侷限性,Node 的出現讓咱們有了第三種選擇,讓 Node 做爲中間層。
具體如何操做?簡單地說就是讓一門後臺語言(好比 Java?PHP?)單純提供渲染頁面所須要的接口,Node 中間層用模板引擎來渲染頁面,使得頁面直出。這樣一來,後臺提供的接口,不只 Web 端可使用,APP,瀏覽器也能夠調用,同時頁面 Node 直出也不會影響 SEO,而且先後端也分離,不失爲一種比較完美的方案。