RegularJS——來自網易的JavaScriptMVC框架

沉默術士發表於2017-06-09

看到 regular 的名字就能感受到撲面而來的山寨味,在開始前,我還是要說明下regularjs出現絕對不僅僅是作者的造輪子情緒氾濫的結果

Angularjs的火爆以及它的小夥伴們

Angularjs從12年開始開始火爆起來, 資料驅動的業務實現方式也由此深入人心, 它的資料更新策略基於髒檢查,在明確內部的生命週期後在資料繫結的使用上是最為靈活的(即這種方式不介意是何種方式促使資料改變,而只關心資料改變的結果),作者本人以及周圍的小夥伴也開始為之著迷. 隨著使用的深入, 發現angularjs的強大特性也引出了一些無法攻克的不足:

由於本身生命週期的強約束,難以與其它框架公用

入門容易,深入難 —— 想想directive一個feature就涉及到的 postlink prelink controller compile scope等等概念.

模板的邏輯實現依賴的是directive(ng-repeat, ng-if etc..),即最小邏輯顆粒是節點, 與常規的模板自由度上還是有較大差異.

FOUC(Flash of unstyled content), 因為angular是先通過瀏覽器(innerHTML)生成了dom,再後置link來產生真正需要的元素,所以會導致內容閃動.regular也沒有完美的解決問題(因為內容仍然是前端render的),但是可以保證進入文件的節點就是預期的節點

除此之外,Angularjs的核心是scope物件, 業務的實現大部分都是在scope上動態新增函式或屬性. 也有人提出整個controller的寫法缺乏約束性,這個時候angular-classy出現, 它將原本因掛載在scope上的業務邏輯轉移到建構函式原型的形式, 減少了靈活度,但是更有約束性, 這也給了regular很大靈感.

在angular大行其道的時期也激勵產生了很多框架,比如vue.js、avalon.js、reactive等等優秀的框架,它們解決了一些問題, 比如avalon.js利用defineProperty實現了資料get-set的代理 並利用VB實現了ie6的相容(當然陣列還是wrap), 但總體來講基於dom實現的新秀們還是缺少足夠的差異化(程式碼量的減少並不是最核心的部分)

新思維的出現——react ractive

與此同時,react的出現讓這個百花齊放但缺少差異化的階段注入了一些不一樣的味道,它可以實現了另一種內建的生命週期(lifecycle), 在不依賴資料層面的髒檢查的同時,建立了ui與資料之間的連線. 它將diff職責放到了一個dom結構的抽象virtual dom上,通過髒檢查兩次render之間virtual-dom發生的變化來更新ui.不過如果移除了jsx的依賴,手動通過巢狀函式的方式建立virtual-dom(如下例)簡直不可忍,並且它的元件展現中的邏輯控制完全依賴與js的語言能力, 往往不像利用模板構建那麼清晰(當然react的作者有它自己的說法,仁者見仁了)。

render: function() { return (
    React.DOM.div(null, 
      React.DOM.h3(null, "TODO"),
      TodoList( {items:this.state.items} ),
      React.DOM.form( {onSubmit:this.handleSubmit}, 
        React.DOM.input( {onChange:this.onChange, value:this.state.text} ),
        React.DOM.button(null, `Add #` + (this.state.items.length + 1))
      )
    )
  );
}

同期ractive也悄然出世, 幾乎就是作者需要的那個菜了. 可惜ractive的ui事件系統是通過代理事件的形式,你仍需要在init裡去處理,這樣一是弱化了宣告式的意味,二是必然要雜糅進dom操作. 並且資料更新上是採用的提取依賴關係的方式並提供set函式, 這種方式對於習慣了angular的髒檢查的人來講無疑會帶來很多不利。

由於react在使用上邏輯上可以幾乎理解為`full-refresh`對使用者有巨大的吸引力,最初版本的regular也是旨在替換掉react的js+jsx而是與ractive一樣定義一種模板語言來描述結構, 在diff策略上沿用virtual-dom的思想.在實現的過程漸漸發現,雖然基於virtual-dom的策略無需去繫結大量的watcher, 但仍然引入了一些實現上和使用上的難題

一次digest中virtual-dom的diff只需一次,但是會隨著ui的複雜度,效能損耗嚴重,virtual-dom與原dom的對應也更難(如果angular的髒檢查的效能取決與watcher的數量,那react則是取決與ui規模)

virtual-dom的內部結構變化是不可預知的

比如

var MyComponent = React.createClass({
 render: function() { if (this.props.first) { return <div className="first"><span>A Span</span></div>; } else { return <div className="second"><p>A Paragraph</p></div>; }
 }
});

在props.first發生改變時, 發生的其實僅僅只是同一個節點的className在first和second的切換. 由於這種未知性,永遠無法在react中出現類似directive的節點增強或包裝器,所有事件也必須以資料代理的形式

regular的產生和取捨

regular正是在這種百花齊放的時候產生, 最終在實現上採取了angular的資料更新策略(但是提取了表示式的依賴關係以便在Object.observe正式到來時切換到髒檢查+observe的形式)提倡極致的宣告式和裸資料操作, 依賴於基於字串的模板描述結構結合更規範性的類式繼承的元件體系來定義資料層的業務邏輯.
文章轉載自 開源中國社群 [http://www.oschina.net]


相關文章