虛擬DOM已死基协?

本系列的上一篇文章《React.Component損害了復用性?》探討了如何在前端開發(fā)中編寫可復用的界面元素菇用。本篇文章將從性能和算法的角度比較 Binding.scala 和其他框架的渲染機制澜驮。

Binding.scala 實現(xiàn)了一套精確數(shù)據(jù)綁定機制,通過在模板中使用 bindfor/yield 來渲染頁面惋鸥。你可能用過一些其他 Web 框架杂穷,大多使用臟檢查或者虛擬 DOM 機制。和它們相比卦绣,Binding.scala 的精確數(shù)據(jù)綁定機制使用更簡單耐量、代碼更健壯、性能更高滤港。

ReactJS虛擬DOM的缺點

比如廊蜒, ReactJS 使用虛擬 DOM 機制,讓前端開發(fā)者為每個組件提供一個 render 函數(shù)溅漾。render 函數(shù)把 propsstate 轉換成 ReactJS 的虛擬 DOM山叮,然后 ReactJS 框架根據(jù) render 返回的虛擬 DOM 創(chuàng)建相同結構的真實 DOM。

每當 state 更改時添履,ReactJS 框架重新調用 render 函數(shù)屁倔,獲取新的虛擬 DOM 。然后暮胧,框架會比較上次生成的虛擬 DOM 和新的虛擬 DOM 有哪些差異锐借,進而把差異應用到真實 DOM 上。

這樣做有兩大缺點:

  1. 每次 state 更改叔壤,render 函數(shù)都要生成完整的虛擬 DOM瞎饲,哪怕 state 改動很小,render函數(shù)也會完整計算一遍炼绘。如果 render 函數(shù)很復雜嗅战,這個過程就會白白浪費很多計算資源。
  2. ReactJS 框架比較虛擬 DOM 差異的過程俺亮,既慢又容易出錯驮捍。比如,你想要在某個 <ul> 列表的頂部插入一項 <li> 脚曾,那么 ReactJS 框架會誤以為你修改了 <ul> 的每一項 <li>东且,然后在尾部插入了一個 <li>

這是因為 ReactJS 收到的新舊兩個虛擬 DOM 之間相互獨立本讥,ReactJS 并不知道數(shù)據(jù)源發(fā)生了什么操作珊泳,只能根據(jù)新舊兩個虛擬 DOM 來猜測需要執(zhí)行的操作鲁冯。自動的猜測算法既不準又慢,必須要前端開發(fā)者手動提供 key 屬性色查、shouldComponentUpdate 方法薯演、componentDidUpdate 方法或者 componentWillUpdate 等方法才能幫助 ReactJS 框架猜對。

AngularJS的臟檢查

除了類似 ReactJS 的虛擬 DOM 機制秧了,其他流行的框架跨扮,比如 AngularJS 還會使用臟檢查算法來渲染頁面。

類似 AngularJS 的臟檢查算法和 ReactJS 有一樣的缺點验毡,無法得知狀態(tài)修改的意圖衡创,必須完整重新計算 View 模板。除此之外晶通,AngularJS 更新 DOM 的范圍往往會比實際所需大得多璃氢,所以會比 ReactJS 還要慢。

Binding.scala的精確數(shù)據(jù)綁定

Binding.scala 使用精確數(shù)據(jù)綁定算法來渲染 DOM 录择。

在 Binding.scala 中拔莱,你可以用 @dom 注解聲明數(shù)據(jù)綁定表達式。@dom 會自動把 = 之后的代碼包裝成 Binding 類型隘竭。

比如:

@dom val i: Binding[Int] = 1
@dom def f: Binding[Int] = 100
@dom val s: Binding[String] = "content"

@dom 既可用于 val 也可以用于 def 塘秦,可以表達包括 IntString 在內的任何數(shù)據(jù)類型动看。

除此之外尊剔,@dom 方法還可以直接編寫 XHTML,比如:

@dom val comment: Binding[Comment] = <!-- This is a HTML Comment -->
@dom val br: Binding[HTMLBRElement] = <br/>
@dom val seq: Binding[BindingSeq[HTMLBRElement]] = <br/><br/>

這些 XHTML 生成的 CommentHTMLBRElement 是 HTML Node 的派生類菱皆。而不是 XML Node须误。

每個 @dom 方法都可以依賴其他數(shù)據(jù)綁定表達式:

val i: Var[Int] = Var(0)
@dom val j: Binding[Int] = 2
@dom val k: Binding[Int] = i.bind * j.bind
@dom val div: Binding[HTMLDivElement] = <div>{ k.bind.toString }</div>

通過這種方式,你可以編寫 XHTML 模板把數(shù)據(jù)源映射為 XHTML 頁面仇轻。這種精確的映射關系京痢,描述了數(shù)據(jù)之間的關系,而不是 ReactJS 的 render 函數(shù)那樣描述運算過程篷店。所以當數(shù)據(jù)發(fā)生改變時祭椰,只有受影響的部分代碼才會重新計算,而不需要重新計算整個 @dom 方法疲陕。

比如:

val count = Var(0)

@dom def status: Binding[String] = {
  val startTime = new Date
  "本頁面初始化的時間是" + startTime.toString + "方淤。按鈕被按過" + count.bind.toString + "次。按鈕最后一次按下的時間是" + (new Date).toString
}

@dom def render = {
  <div>
    { status.bind }
    <button onclick={ event: Event => count := count.get + 1 }>更新狀態(tài)</button>
  </div>
}

以上代碼可以在ScalaFiddle實際運行一下試試蹄殃。

注意携茂,status 并不是一個普通的函數(shù),而是描述變量之間關系的特殊表達式诅岩,每次渲染時只執(zhí)行其中一部分代碼讳苦。比如带膜,當 count 改變時,只有位于 count.bind 以后的代碼才會重新計算医吊。由于 val startTime = new Date 位于 count.bind 之前钱慢,并不會重新計算,所以會一直保持為打開網頁首次執(zhí)行時的初始值卿堂。

有些人在學習 ReactJS 或者 AngularJS 時,需要學習 key 懒棉、 shouldComponentUpdate 草描、 $apply$digest 等復雜概念策严。這些概念在 Binding.scala 中根本不存在穗慕。因為 Binding.scala 的 @dom 方法描述的是變量之間的關系。所以妻导,Binding.scala 框架知道精確數(shù)據(jù)綁定關系逛绵,可以自動檢測出需要更新的最小部分。

結論

本文比較了虛擬 DOM 倔韭、臟檢查和精確數(shù)據(jù)綁定三種渲染機制术浪。

表格

這三種機制中,Binding.scala 的精確數(shù)據(jù)綁定機制概念更少寿酌,功能更強胰苏,性能更高。我將在下一篇文章中介紹 Binding.scala 如何在渲染 HTML 時靜態(tài)檢查語法錯誤和語義錯誤醇疼,從而避免 bug 硕并。

相關鏈接

更多精彩洞見,請關注微信公眾號:ThoughtWorks

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末秧荆,一起剝皮案震驚了整個濱河市倔毙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乙濒,老刑警劉巖陕赃,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異琉兜,居然都是意外死亡凯正,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進店門豌蟋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來廊散,“玉大人,你說我怎么就攤上這事梧疲≡识茫” “怎么了运准?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長缭受。 經常有香客問我胁澳,道長,這世上最難降的妖魔是什么米者? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任韭畸,我火速辦了婚禮,結果婚禮上蔓搞,老公的妹妹穿的比我還像新娘胰丁。我一直安慰自己,他們只是感情好喂分,可當我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布锦庸。 她就那樣靜靜地躺著,像睡著了一般蒲祈。 火紅的嫁衣襯著肌膚如雪甘萧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天梆掸,我揣著相機與錄音扬卷,去河邊找鬼。 笑死沥潭,一個胖子當著我的面吹牛邀泉,可吹牛的內容都是我干的。 我是一名探鬼主播钝鸽,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼汇恤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拔恰?” 一聲冷哼從身側響起夹厌,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤歪泳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敏弃,經...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡疾牲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年变丧,在試婚紗的時候發(fā)現(xiàn)自己被綠了沙庐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡咸这,死狀恐怖夷恍,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情媳维,我是刑警寧澤酿雪,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布遏暴,位于F島的核電站,受9級特大地震影響指黎,放射性物質發(fā)生泄漏朋凉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一醋安、第九天 我趴在偏房一處隱蔽的房頂上張望杂彭。 院中可真熱鬧,春花似錦茬故、人聲如沸盖灸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至醉箕,卻和暖如春钾腺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背讥裤。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工放棒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人己英。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓间螟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親损肛。 傳聞我的和親對象是個殘疾皇子厢破,可洞房花燭夜當晚...
    茶點故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內容