1. 程式人生 > >前端模板技術面面觀(1)

前端模板技術面面觀(1)

水平 雲服務 簡單 驗證 ebs 很慢 分離 src body

此文已由作者鄭海波授權網易雲社區發布。

歡迎訪問網易雲社區,了解更多網易技術產品運營經驗


此文的寫作耗時很長,稱之為雄文不為過,小心慢用

此文緣由

其實從發布regularjs之後,我發現在google搜索regularjs 不是給我這個畫面

技術分享圖片


就是給我這個畫面

技術分享圖片


突然發現取名字真是個大學問,當時就基本預計到了會有不明真相的朋友認為它只是一個照搬angularjs的家夥,對於這點,有興趣的朋友可以看下【為什麽要造Regularjs這個輪子】。

而在這個文章,我不會直截了當去與angular做直接的對比,而是從最基本原理開始對現有的模板解決方案進行一個全面的分類,同時會給出它們的一些或優或劣的特性,這些特性基本都是本質性的,即它不為維護者的水平高低和勤勉與否所限制,所以是具有客觀性的。

什麽是模板解決方案?

你可以先簡單的理解為模板引擎。

事實上前端的模板解決方案已經從 “選出一個好用的模板好難” 發展到了 “從這麽多模板中選一個好難的”的階段,Template-Engine-Chooser!似乎也開始無法跟上節奏了。再加上目前Dom-based的模板技術的崛起(angularjs, knockout等),漸漸讓這個領域有亂花漸欲迷人眼的感覺。

這篇文章會對當今前端界的三種截然不同的模板方案做一個全面的對比,它們分別是

  1. String-based 模板技術 (基於字符串的parse和compile過程)

  2. Dom-based 模板技術 (基於Dom的link或compile過程)

  3. 雜交的Living templating 技術 (基於字符串的parse 和 基於dom的compile過程)

同種類型的模板技術的可能性都是相同的,即同樣身為dom-based的vuejs如果願意可以發展為angularjs的相同功能層級。

(註: 其實這麽說作者後續思考後覺得並不是很妥當,因為決定這類框架的還有重要一環就是它們的數據管理層:,比如是基於臟檢查還是基於setter和getter,就會有截然不同的定位)

另外需要註意的是任何一種類型的模板技術都是不可被替代的,它們甚至可以結合使用,並且很長一段時間內還會繼續共存下去。

除此之外另外一種奇葩模板技術本文也會提到即react,了解後你會發現它的特性更接近於Living templating。

在進入介紹之前,我們需要先過一下不得不說的 InnerHTML,它是本文的關鍵因素。

innerHTML

我不認為還需要從innerHTML的細節講起,我們對它太熟悉了,那就直接從優劣開始講吧!

innerHTML 毫無疑問是好的

在innerHTML正是成為 web 標準 前,它當之無愧的已經是大家公認的事實標準,這是因為:

1 . 它便於書寫並且直觀

想象下你必須添加如下的html到你的文檔裏

<h2 title="header">title</h2>
<p>content</p>

直接使用 innerHTML

node.innerHTML = "<h2 title="header">title</h2><p>content</p>"

在對比使用Dom API

var header = document.createElement('h2');
var content = document.createElement('p');
h2.setAttribute('title', 'header');
h2.textContent = 'title';
p.textContent = 'content';
node.appendChild(header);
node.appendChild(content);

innerHTML 毫無疑問贏得了這張比賽.

盡管部分框架例如mootools:Element 提供了高效的API來幫助你創建dom結構,innerHTML仍然會是大多數人的最佳選擇

2 . 它很快,特別在old IE

隨著瀏覽器的發展,這個測試可能越來越不符合實際,innerHTML和 Dom Level 1創建dom結構的差距正變得原來越小

3. 它完成進行了String -> Dom的轉換

這個論點有點拗口,事實上後續要提到的兩類模板技術都是因為這個特點而與其有了強依賴

然而我們又清楚的被告知:

The recommended way to modify the DOM is to use the DOM Level 1 API. ——Chapter 15 of "Javascript: The Definitive Guide_"

為什麽?

innerHTML 有時候又是不聽話的

1. 安全問題

innerHTML 具有安全隱患.,例如:

document.body.innerHTML = "<img src=x   onerror='alert(xss)'/>"

我知道像你這樣優秀的程序員不會寫出這樣的代碼,但當html片段不完全由你來控制時(比如從遠程服務器中),這會成為一個可能引爆的炸彈。

2. 它很慢

等等,你剛才說了它很快! 是的,但是如果你僅僅為了替換一個屬性而用innerHTML替換了所有的Dom節點,這顯然不是一個明智的決定,因為你深知這是低效的。所以說:

Context is everything

所有離開背景談的性能、功能、性功能都是偽科學

3. 它很笨

它會完全移除所有現有的Dom,並重新渲染一遍,包括事件和狀態都以不復存在,這點利用innerHTML來進行render的框架(例如Backbone)的開發者應該深有體會,為了減少損失,不能不把View拆的越來越細,從而抱著看似“解耦完美”的架構體系進入了維護的深淵。

註: 其實react的最大貢獻就是它差不多是提供了一個更smart的innerHTML解決方案。

4. 有可能會創建出意料之外的節點.

由於html的parser非常的“友好”, 以至於它接受並不規範的寫法,從而創建出意料之外的結構,而開發者得不到錯誤提示。

好了,到現在為止,我們大概了解了innerHTML這個朝夕相處的小夥伴,接下來我們正式聊一聊模板技術,首先我們從最常見的“String-based templating”開始

String-based templating

基於字符串的模板引擎最大的功勞就是把你從大量的夾帶邏輯的字符串拼接中解放出來了,由於它的完全基於字符串的特性,它擁有一些無可替代的優勢。

It is essentially a way to address the need to populate an HTML view with data in a better way than having to write a big, ugly string concatenation expression. --- cited from http://www.dehats.com/drupal/?q=node/107

示例

  1. mustache及其衍生: 弱邏輯

  2. Dust.js: 強邏輯 (推薦)

  3. doT.js: 超級快

基本原理

技術分享圖片


如上圖所示,我們發現字符串模板強依賴於innerHTML(渲染), 因為它的輸出物就是字符串。由於這篇文章的重點不在這裏,我們不會再對它們如何使用作深究。

優點

  1. 快速的初始化時間: 很多angular的簇擁者在奚落String-based templating似乎遺漏了這一點。

  2. 同構性: 完全的dom-independent,即可作為用服務器端和瀏覽器端(客官先不要急著搬phantomjs哈).

  3. 更強大的語法支持:因為它們都是不是自建DSL就是基於JavaScript語法,Parser的靈活性與受限於HTML的Dom-based模板技術不可同日而語

缺點

  1. 安全隱患: 見innerHTML

  2. 性能問題:見 innerHTML.

  3. 不夠聰明: 見innerHTML(呵呵),除此之外render之後數據即與view完全分離。

盡管在這幾年的發展之下,由於異常激烈的競爭,基於字符串的前端模板技術變得越來越快,但是它們顯然大部分都遺漏了一些問題

  1. 大俠們你們沒有考慮進把輸出字符串加載到Dom的時間,這才是真正瓶頸之一

  2. 不在相同功能前提下的對比有意義麽?

Dom-based Template Engine

近幾年,借著Angularjs的東風,Dom-based的模板技術開始大行其道,與此同時也出現了一些優秀的替代者,就我們國人而言,近的就有@尤小右的Vuejs 和 司徒大大的avalonjs。看倉庫就可以發現風格也是完全不同:1) 一個簡潔優雅 2)一個奔放不羈

示例

  1. Angularjs: 都28000star了還需多說麽

  2. Knockout: 在此領域內,對Web前端而言是鼻祖級的

大致流程

技術分享圖片


Dom-based的模板技術事實上並沒有完整的parse的過程(先拋開表達式不說),如果你需要從一段字符串創建出一個view,你必然通過innerHTML來獲得初始Dom結構. 然後引擎會利用Dom API(attributes, getAttribute, firstChild... etc)層級的從這個原始Dom的屬性中提取指令、事件等信息,繼而完成數據與View的綁定,使其"活動化"。

所以Dom-based的模板技術更像是一個數據與dom之間的“鏈接”和“改寫”過程。

註意,dom-based的模板技術不一定要使用innerHTML,比如所有模板都是寫在入口頁面中時, 但是此時parse過程仍然是瀏覽器所為。

優點

  1. 是活動的: 完成compile之後,data與View仍然保持聯系,即你可以不依賴與手動操作Dom API來更新View

  2. 是運行時高效的: 可以實現局部更新

  3. 指令等強大的附屬物幫助我們用聲明式的方式開發APP

缺點

  1. 部分請見innerHTML

  2. 沒有獨立的Parser,必須通過innerHTML(或首屏)獲取初始節點,即它的語法是強依賴與HTML,這也導致它有潛在的安全問題

  3. 信息承載於屬性中,這個其實是不必要和冗余的。 部分框架在讀取屬性後會通過諸如removeAttribute的方式移除它們,其實這個不一定必要,而且其實並無解決它們Dom強依賴的特性,比如如果你查看[angular的todomvc]的節點,你會發現它的輸出是這樣的:技術分享圖片

  4. FOUC(Flash of unstyled content):即內容閃動,這個無需多說了,只怪它初次進入dom的內容並不是最終想要的內容。


免費領取驗證碼、內容安全、短信發送、直播點播體驗包及雲服務器等套餐

更多網易技術、產品、運營經驗分享請點擊。


相關文章:
【推薦】 使用Phaser開發你的第一個H5遊戲(一)

前端模板技術面面觀(1)