照片出處: http://www.geograph.org.uk/photo/360000 作者: Barbara Voules

兩年前初見Knockout.js後便一腳踏入MVVM世界無法回頭。學習簡單很快上手,用Knockout做出錯誤少又容易擴充維護的AJAX網頁。在此之前,為了讓欄位連動,總要寫一堆<input>、<select> onchage、onclick事件,事後常需要在一堆事件程式碼裡追查更動來源,更糟的是稍一調整就常因觸發順序改變導致錯誤,修改維護是件苦差事;改用KO後,專心把ViewModel邏輯寫好,餘下的欄位連動便能一次到位,加上邏輯都集中寫在ViewModel內,維護起來輕鬆許多。

不過,最近參與SPA專案(Single Page Application,指從頭到尾沒有任何PostBack,停在同一網頁裡完成全部工作的網頁,最經典的例子是Gmail),逐漸感受單靠Knockout(或者該說MVVM)的不足。SPA需在同一網頁切換不同操作介面,當介面複雜度提高,網頁HTML、JavaScript開始龐大交錯,管理及維護難度急速上升。面對這類情境,引用JavaScript端MVC設計模式讓架構分明,簡化維護難度,是較好的選擇,而Knockout只專注於MVVM,仍需要其他MVC架構輔助才容易建構成SPA。

經過粗淺評估,目前市場上較常提及的JavaScript MVC架構包含: AngularEmberBackboneDurandal(杜蘭德爾,中古世紀聖騎士羅蘭的配劍名字)。由於我的後端一定是用ASP.NET MVC開發,故整合資源、參考資料的多寡將是考量關鍵,以此標準,就是Angular JS或Durandal二選一了。

Angular JS擁有最大的開發社群,是幾個架構中最夯的,氣勢驚人。而選擇Durandal的優勢在於Knockout! MVVM也算是MVC裡的一環,Angular有自己一套處理MVVM的做法,而Durandal則直接採用Knockout處理MVVM,微軟傳教士John Papa也曾針對Durandal有一系列的介紹,對我而言,已累積的KO知識在應用Durandal時將可發揮,感覺上Angular與Durandal各有優勢。看似兩難的抉擇,其實至今局勢已大幅改變~

在今(2014)年初,Open Source的Durandal啟動了一個集資計劃(Kickstarter),雖然創始人Rob聲明說即使集資不成仍會持續發展,只是開發速度趨緩,但已令人憂心Durandal的發展動能及前景。到了4月中,Angular的部落格上有篇很特別的文章,作者是Rob Eisenberg -- 是的,就是剛說的Rob,Durandal的創始者(Rob還打趣的說,大家不要驚慌,他不是靠Heartbleeding漏洞駭進Angular Blog偷發文),文中透露驚人的消息。Rob從2月起已加入Angular Core 2.0 Team,計劃將原本Durandal下一代(NextGen)的構想融入Angular 2.0,同時提供Durandal 2.x遷移到Angular的途徑,Durandal 2.x仍會繼續維護(但可預期將不再有新版本),此舉如同宣告Durandal的發展已劃上句點。

發展至此,微軟不再(也無法)漠視Angular的成長並開始擁抱Angular(令我憶起當年AJAX Control與jQuery的瑜亮故事),John Papa近期有愈來愈多談Angular整合的文章,前陣子結束的北美TechEd還有場談ASP.NET+Angular建立RIA的議程。由此不難得感受,使用Angular建構ASP.NET SPA已是當今的主流!

最後,我很倚重的Kendo UI元件為Angular再下一成。前陣子發表Angular Kendo UI v1.0,方便Angular整合Kendo UI,雖然KO也有社群發展的knockout-kendo可用,但Angular Kendo UI由官方推出,二者層級有別,也算Angular穩坐前端MVC一哥地位的佐證。

分析至此,態勢明顯,如果要走ASP.NET SPA,Anuglar才是主流選擇!! 廢話不多說,立刻向Angular出發~

但,Knockout該何去何從?

首先得強調一點,Knockout根本不是Angular的對手!! 倒不是因為Angular太強大,KO還沒上擂台就被叫去領便當;而是二者定位不同,KO只專注於MVVM,而Angular包含整套MVC。MVVM所聚焦的Data Binding只是MVC中實做View的一環,故二者不該直接相比,就像沒人會拿Office跟iPhone相比一樣道理,要比也是Windows Phone對上iPhone,定位才相近。Angular是完整的MVC架構,真要比較,對手應該是Durandal、Ember或Backbone,而Knockout隸屬Durandal陣營,所以應是Durandal vs Angular,哦哦...

這段時間,其實我已投入不少時間熟悉了解AngularJS,Angular在語法簡潔性(自訂Directive及Filter的概念很酷)、架構彈性(可動態載入切換View、Dependency Injection的點子很棒)、可維護性(甚至已考慮自動測試需求)方面考慮嚴謹周延,常讓我發出讚嘆(回頭看到自己的土砲架構,不禁發出感嘆)。但在Binding運作上,Angular不像KO靠宣告observable()、observableArray()建立依賴關係,而是直接觀察Scope內JavaScript物件的改變自行建立相依。雖然Angular宣告ViewModel時不必寫成observable()、observableArray()很省事,但面臨較複雜的欄位互動邏輯,初學者常難以判斷某個動作是否會被Angular感測。除此之外,Angular涉及MVC,整體架構範圍比MVVM龐大,而官方技術文件較Knockout深澀。依我個人看法,Angular的學習曲線較Knockout陡峭許多。在一些簡單的ASP.NET AJAX應用場合,如果只是需要一套MVVM機制,Knockout較好學習上手,而observable/observableArray宣告雖然囉嗦,但應用時容易區分是否觸發UI連動,還是很有優勢。

至於我的選擇? 由於專案會走向SPA,Angular是強大、完整、嚴謹、彈性的主流MVC架構工具,並已廣為ASP.NET社群接受,就算學習曲線陡峭如同單攻奇萊主峰,也得咬牙吞下去,著眼熟悉活用後帶來好處。近期將會陸續分享我的Angular學習筆記,一連串KO之後,NG要上場囉~


Comments

# by Eric

鳴~~黑大您終於來了(擦眼淚~~) 最近一直在跟 angularjs + kendo ui mobile 纏鬥. 在研究的路上是狐獨的(挺~~) 終於看到我的明燈也要跳進來. 跟黑大討論的小問題. 為什麼 2個contoller 之間的資料交換要透過 service ? 小弟知其然,不知其所以然,望黑大指點一二.

# by e-Cheng

hi, Eric 因為兩個controller本身是不同實例, 有各自的$scope https://docs.angularjs.org/guide/controller

# by Eric

Hi e-Cheng, 謝謝你的回答. 為什麼不能由 A Controller 呼叫 B Controller所提供的method , 是因為 在A controller 裡只能看到自己scope裡的東西. 看不到外面, 所以要透過inject 的 service來跟外面溝通?

# by Jeffrey

to Eric, 我認為Controller不能直接互通是為了貫徹SoC(關注點分離)! Controller的職責是結合資料(Model/ViewModel)與View,眼裡應該只看得到經手的資料與要接觸的View,除此之外就是跨Controller共用的服務,不該知道有其他Controller存在。這麼做的好處在於避免Controller間產生相依性。不然會變成網站裡如果要使用Controller A,就一定要有Controller B,否則無法運作,就架構設計角度有些奇怪,有點像買了BMW還得買Benz才能開上路(當然啦,姑且不論一次雙B把妹有開無雙的效果 XD),將必備的部分拉出來成為獨立服務,就維護、測試的觀點比較符合直覺。

# by Eric

☆_☆ 哇... 黑大一席話,勝讀10年書. 我也想要開無雙把妹..(一整個畫錯重點) 再跟黑大請教個觀念問題. 在需要透過webapi 向 server 讀取資料時, 是由誰負責? 由誰啟動? 我想象中是 Controller 經由service 透過 $http 讀取 server上的資料後. 用broadcast的方式讓 Controller 知道後,讓Controller 把資料填到 view裡面 . 是這樣嗎?

# by Jeffrey

to Eric, 依MVC角色設計,UI串連及資料流動由C主控,故由Controller透過$http(模規大一點的專案會將資料同步功能獨立成service)發動取得資料是對的,至於API設計可以用getViewModel()傳回ViewModel,或是將ViewModel物件交給Service將資料填進去。

# by Eric

目前看到的新手教學很少有提到整合的應用 ∑( ̄□ ̄;) 所以對這段不是很懂 "至於API設計可以用getViewModel()傳回ViewModel,或是將ViewModel物件交給Service將資料填進去" 求黑大詳細. m(_ _)m

# by Jeffrey

to Eric, 這個議題未來會有專文介紹,目前我的研究還有限,但大致的概念如這個範例: http://jsbin.com/releq/1/edit。mySvc即所謂共用服務,其中dataHelper是Singleton,即所謂"用getViewModel()傳回ViewModel"(但由於$http為非同步,取資料要寫在.success()),而dataAgent為一個Controller建一個Instance,故一開始傳入ViewModel給它,之後呼叫.read()請它取資料填入。

# by programlin

Angular也是有其缺點,就是他並沒有一套完整的UI做整合,目前JS在UI方面並沒有一個好的機制能夠在不同框架間做整合,所以選定UI代表幾乎也選定開發方式. 所以我反而比較推薦用ExtJS這個框架,從架構到UI一應具全,也發展了這麼多年,資料取得容易,新版也開始支持MVVM. ExtJS不單單設計框架 UI框架,還包含很多語言層擴展,資料存取部分等這些是其他框架所欠缺的. JS發展至今一直存在個問題,就是除了語言外沒有甚麼標準,導致拼湊起來的技術常常無法整合,我認為這也是因為出在語言本身就不是個嚴謹規範的語言.

# by Joker

extjs , 拜托.... 千人一面

# by 张吊富

。。。。。

# by JOJO

Durandal 和 Html5 的validation 有冲突吗?

# by Jeffrey

to JOJO,對 Durandal 亳無研究,不好意思幫不上忙。

Post a comment