淺談前端

近年來隨着Web應用交互複雜度的提升,前端開發也迎來了一個高速發展的時期。除了一些老牌框架紛紛推出改動較大的升級之外,還涌現出一批新生代的開源庫和框架,推動着Web應用開發理念向越來越強調前端架構的方向發展。當下的前端技術可以說是處在一個新舊交替的過程之中,同時存在着許多不同的觀念和實踐。

本文試圖對目前數量繁多的前端框架進行一些較籠統的分析和比較,拋磚引玉,希望能爲大家在選擇前端的技術架構時提供一些有益的參考。需要明確的是,本文探討的前端架構是以JavaScript爲主。有一些主要關注CSS層面的前端框架,如Bootstrap,不在本文的討論範圍之內。

今天的JavaScript框架和庫繁多複雜,很大程度上源於Web前端開發本身的特殊性。從當初的可有可無到今天各種功能完備的HTML5標 準,JavaScript在Web應用中的職責和定位經歷了巨大的變化。加上長期以來各種瀏覽器對ECMA標準支持參差不齊的複雜環境,這導致大家對於 JavaScript能做什麼、該做什麼、應該怎麼做一直無法形成共識。一個Web應用可以把所有業務邏輯全部放在服務器端,幾乎不依賴 JavaScript;也可以完全用JavaScript構建客戶端,服務器只負責數據接口;更有可能選擇介於兩者之間的折中方案。整體架構選擇的多樣性 使得不同的應用對於前端架構有着截然不同的需求。這意味着很難有一個前端庫或框架可以滿足所有人,也使得開發者在找不到完美方案的情況下選擇重複造輪子。 同時,由於JavaScript是一門相當靈活的語言,不同背景的開發者借鑑了許多不同的軟件設計思想來構建他們理想中的JavaScript框架,這也 導致不同的框架/庫在解決同一個問題時經常有不同的方案,例如單頁應用的設計模式問題。

框架vs.庫

衆所周知,在前端開發中對於庫(Library)和框架(Framework)的區分向來是有些模糊的。像jQuery、YUI這些項目的官方描述都是 “庫”,卻經常在各種地方被人們稱作“框架”。近兩年出現的一些MVC項目號稱框架,實際上卻更像庫。此外,在同樣號稱框架的各個項目之間所覆蓋的功能也 都有所不同。傳統軟件工程對於庫和框架的區分主要着眼於對應用運行流程的控制權。框架提供架構,控制運行流程,讓開發者在合適的地方書寫針對具體問題的代 碼;而庫則附屬於架構,不控制運行流程,只提供可調用的函數。但由於上述Web前端開發的特殊性,這樣的定義顯得有些過於嚴格:真正稱得上框架的項目很 少,卻又經常需要和作爲庫的項目進行比較。因此,在比較JavaScript開源項目時,是框架還是庫並不特別重要,首先應該分析該項目覆蓋了前端開發中 的哪些問題(下文爲了論述方便,一律用框架指代各類JavaScript開源項目)。

前端開發可能面對的需求

前端開發中最常見的問題大致可以分爲:封裝原生API和常用任務、基礎架構、富應用架構、視覺交互,以及工具鏈。下面我們逐個分析。

封裝原生API和常用任務

JavaScript的原生API存在以下問題。

  • 對象、方法名煩瑣。
  • 缺少一些常用任務的語法糖。
  • 舊瀏覽器兼容性不佳。

因此早期的一些框架最主要的目標就是把煩瑣的原生API和常用的任務封裝成更簡潔直觀的API,同時,在封裝過程中也處理了兼容性問題。jQuery就是解 決這一部分問題的典型方案。HTML5和ECMAScript 5標準的出臺使得這些問題有所好轉。隨着新標準的普及,將來對於這一部分功能的需求會逐漸減弱。通常來說,封裝的對象包含以下類別。

  • DOM的選擇和操作:經典的例子如jQuery的鏈式API。
  • DOM事件處理:一個重點是簡化事件的delegation,即利用事件冒泡機制在父元素上用一個偵聽函數偵聽觸發在多個子元素上的事件。
  • Ajax:簡化煩瑣的XMLHttpRequest API,並且加強其語義性。
  • 語言增強:主要提供一些對數組和對象進行操作的便利函數。jQuery包含一些,但更典型的有Underscore和Lodash。

基礎架構

這一部分通常是各類框架中比較底層的功能,決定了採用此框架的代碼是如何被組織到一起的。目標是提高代碼的可維護性、可協作性和可測試性。

模塊管理:對大型的JavaScript項目來說,模塊化開發是必需的。有些框架只提供基本的模塊註冊機制以防止全局變量污染和衝突,而另一些則提供包括 模塊依賴解析、文件加載、壓縮打包的功能。目前JavaScript模塊管理有兩個互相競爭的標準,一個是AMD(Asynchronous Module Definition),採用的框架有Dojo,單獨的模塊管理庫有RequireJS;另一個是CommonJS的模塊標準,採用者有模塊管理庫 SeaJS,以及基於SeaJS的開放型框架Arale。面向對象:JavaScript有原型繼承,並且可以非常靈活地進行動態混入,但很多大型項目還是需要一個統一的面向對象的繼承/擴展系統。對 此,John Resig、Douglas Crockford、Nicholas Zakas等各路JavaScript大神都曾經進行研究並給出過各自的解決方案,許多框架中也包含類似的解決方案。對此感興趣的同學推薦閱讀Arale 文檔中的這篇文章: http://aralejs.org/class/docs/competitors.html

自定義事件系統:爲了提高模塊的可複用性、整個系統的容錯性和靈活性,各個模塊之間需要儘量解耦,使得相互之間儘可能減少依賴。要實現這樣的解耦,一個自定義的事件機制 (通常借鑑Pub-Sub、Observer、Mediator等設計模式) 是很好的手段。

組件系統:定義如何使用和書寫組件、組件之間如何相互調用和通信等。

富應用架構

這一部分的主要目的是利用設計模式進一步提高代碼複用,使得開發者的精力可以主要集中在實現應用本身的功能上。

代碼邏輯分層:把對視覺界面、交互邏輯和數據的處理清晰地分開。就這一點而言,大部分框架借鑑了經典的MVC模式,但傳統的MVC在前端並不適合直接套 用,因此各個框架對此的處理都略有不同,有些採用了MVP(Model-View-Presenter)或是MVVM(Model-View- ViewModel)模式。著名前端佈道師Addy Osmani有詳細的分析,本文受篇幅所限不再贅述。

數據綁定:把界面和數據模型進行綁定,使得一方變化的時候另一方也會自動變化,可以省去手動更新DOM的操作。

數據與服務器端的同步:服務器端提供符合REST規範的API,前端的數據模型可以封裝同步操作,可以省去手動發送Ajax請求的過程。

模板渲染:在前端存儲和渲染可複用的HTML模版,這樣更新界面時不需要再向服務器發送額外的請求。

URL路徑、應用狀態和歷史管理:無論是從搜索引擎還是用戶體驗的角度來看,大型單頁應用都應該提供和應用的狀態相對應的URL,同時不破壞後退鍵的功能。

視覺交互

傳統型大框架會包含這部分內容,通常是基於自身架構上的擴展,對框架自身有依賴性。但一些新框架則只專注於架構,對擴展部分徹底持開放態度,提倡讓開發者自己選擇最合適的工具。

效果和動畫:用原生JavaScript實現動畫是一個比較煩瑣的過程,尤其是當需要精確的時間和緩動(easing)處理時。因此一些框架如jQuery提供一個API簡潔的動畫引擎,並封裝了常見的動畫效果。

UI組件庫:這是傳統型的大框架的主要賣點之一,大量現成的UI組件以及與框架本身的親和性,可以大幅提高開發效率。YUI、Dojo是典型代表。在選擇時,需要注意的一點是可定製性。

數據繪圖:這是一類比較特定的需求,但其實現的複雜程度也非常高。ExtJS封裝了強大的數據圖表功能,除此之外也有專門針對數據可視化的庫如D3.js。

工具鏈

隨着前端項目越來越大,維護和上線的流程也越來越複雜。利用好各類工具實現自動化,可以大幅提高效率。隨着Node.js社區的迅猛發展,各類基於JavaScript的命令行工具大量出現,這其中就有許多針對前端開發的優秀項目。

編譯工具:這裏的編譯嚴格來說是指js的組合和壓縮。通常大型項目都會有多達幾百KB的js文件,採用模塊化開發的話,文件數量也會非常龐大,進行壓縮打 包是必不可少的過程。大型框架如Closure Library、Dojo、YUI都自帶編譯工具。如果使用了模塊管理庫,例如RequireJS和SeaJS,也可以使用它們自帶的打包工具。其他情況 下則可以自己寫build script,也可以藉助任務化的編譯工具如Grunt.js或者Jake。

包管理工具:很久以來,前端開發者都需要自己下載、管理各類第三方庫。前端的包管理機制的好處是可以更方便地管理第三庫的版本和相互之間的依賴。目前國外 比較流行的單純的前端包管理工具有Twitter的Bower,也有混合了包管理和編譯於一體的Ender.js和Volo.js,更有集組件框架、包管理和編譯於一體的Component。國內方面,SeaJS提供包管理+編譯工具spm。

單元測試工具:前端也需要單元測試。同樣的,傳統的大型框架也大多自帶單元測試工具。單獨的測試框架中比較流行而且簡單易用的有QUnit、 Jasmine、Mocha等。此外,還有一些更復雜的前端測試框架,包含了在各類瀏覽器裏的自動化測試,這又可以單獨開出一個話題,限於篇幅不再深入, 感興趣的朋友可以參考: http://stackoverflow.com/questions/300855/looking-for-a- better-javascript-unit-test-tool

框架的分類

以下根據風格對一些主流框架進行了粗略的分類,但分類並不是絕對的,只是爲了簡化比較的過程。

封裝型

典型如jQuery、MooTools,國內則有百度的Tangram。這一類框架通常只針對上述需求列表中的“封裝原生API”這一塊。雖然有插件機制,但通常不提供任何架構方面的幫助,因此現在更多的是和架構類的輕量框架搭配使用。

傳統型

典型如Dojo、YUI、Closure Library、ExtJS等,國內則有阿里的KISSY、網易的NEJ、騰訊的JX等。支付寶玉伯將這一類比喻爲“大教堂風格”,一般有這些特點:穩 定,經受過實戰的考驗;覆蓋的問題全面,試圖在自身範圍內解決儘可能多的問題;代碼風格和質量一致,也經常會要求使用者遵循一定的風格規範;文檔豐富詳 細;更新穩重、緩慢;排他性,一旦選擇很難替換;通常帶有UI組件庫。

開放型

就國內外的典型例子來說,國外有由Node.js著名活躍開發者TJ Holowaychuck所牽頭的Component( https://github.com/component/component),國內則有阿里的Arale和豆瓣的Oz。

開放型的框架專注於提供開放的基礎架構,即代碼組織方式和工具鏈。它們也提供一部分現成的模塊,但使用者可以靈活地書寫模塊,或是博採衆家之長,將第三方的庫整合爲模塊來使用,又被稱之爲“集市風格”。

  • 靈活,可以適應不同類型的架構需求。
  • 用不同庫解決不同問題,解耦性好。
  • 社區活躍,更新迅速。
  • 代碼風格質量不一。
  • 選擇和整合第三方庫時需要很多精力。

單頁應用型

代表性的如Backbone.js、Ember.js、AngularJS、Knockout.js等。單頁應用的優勢是服務器請求數少、UI反應快速、用戶體驗流暢。對於交互複雜的大型應用,尤其需要有一個爲單頁應用量身打造的前端架構來支撐。

這一類框架在近兩年大量涌現,如上文所說,存在着許多不同的觀點。

  • 首先是架構採用什麼模式:是MVC(Ember.js、AngularJS)、MVP(Backbone.js)還是MVVM(Knockout.js)?
  • 其次是侵入性:侵入性較強的提供更多的架構支持,但學習曲線也更陡峭一些(Ember.js、AngularJS);侵入性較弱的則上手更快,和其他框架/庫更容易兼容(Backbone.js、Knockout.js)。
  • 最後是View的處理:是由JavaScript來把基於String的模板渲染成DOM(Ember.js、Backbone.js),還是由JavaScript爲已有的DOM添加行爲(AngularJS、Knockout.js)?

這些問題目前還沒法得出決定性的結論,更多的是看開發者的個人偏好和習慣更適應哪一種。好在這類框架目前社區都相當活躍,因此可以找到不少參考。

值得一提的是,一些老牌的傳統型框架如Dojo、YUI、ExtJS都開始引入了MVC單頁應用架構。但Dojo和YUI的這部分功能仍處在比較粗糙的階段,只有ExtJS進行了整體重大升級,相對成熟一些。

特例

Twitter在2月初剛開源了它的前端框架Flight。這是一個介於單頁應用型和開放型之間的框架。其核心是事件驅動的、基於DOM的組件機制。它強調組件之間相對獨立鬆散的架構,但對組件的寫法定義十分嚴格,具有一定的侵入性和排他性。

選擇框架時應該考慮什麼

項目規模:小項目需要快速迭代,需要靈活性較高、兼容性比較好的架構。而大項目則需要關注成熟度、風格規範、可協作性、可維護性和可測試性。

團隊的現有資源:團隊是否對後臺技術選擇和架構有一定的偏好?是否已經對某些框架/工具有實戰的經驗?如果選擇一個開放式的框架,是否有足夠的精力來整合各類第三方工具?最後,選擇一個團隊不熟悉的框架,需要衡量帶來的好處是否能抵消掉學習成本。

產品對用戶體驗的需求:產品本身更適合做成單頁應用還是傳統Web應用?產品是需要大量現成的UI組件,還是需要注重每一個細節?

建議在選擇框架時,首先對自己的項目和團隊進行定位,然後總結出具體的技術需求列表,最後參照上文列舉的各項細節來尋找適合的框架和周邊工具。當然,本文無法窮舉所有的細節,只能提供大致的選擇方向。確定幾個潛在選擇之後,還需要開發者自己進行深入的研究和試用。

總結

前端技術正處在一個新老並存、百家爭鳴的時代。一方面我們需要等待HTML5以及其他W3C標準的普及,另一方面更新的標準,如Web Components和ECMAScript 6又已在起草之中。這兩個標準普及時,前端架構恐怕又會迎來一次洗牌。但不管怎樣,做好足夠的功課,然後根據自己的實際需求出發來進行選擇總是沒錯的。

發佈了15 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章