HTML5 時代來臨,使用原生代碼編寫 Native App 還是使用 HTML5 技術構建 Web App 的爭論還未塵埃落定。但不可否認的是,Web 前端正變得越來越重,處理的邏輯越來越複雜。不僅僅是交互體驗需要編寫大量 javascript 代碼,甚至很多業務邏輯都被搬到了前端。例如有些 購物車 的設計,無需向服務器端發送請求即可向購物車中添加商品並立刻計算出總價格。Web 的功能越來越強,javascript 代碼越來越多,如何組織這大量的 js 成為亟待解決的問題。

一、前端 MVC

MVC 是一個不錯的方案,它崇尚代碼分離以及有效的分工模式。在傳統的 Web 後端開發過程中,Models 是數據對象,它實現了對數據源的增刪改查,並且大部分人把業務邏輯也放在這裡;View 是用戶界面,將處理過的數據結果呈現給用戶;Controller 用來轉發請求連接這兩者。

想象一下,我們把這套行為準則搬到前端。

Ajax 在 Web 2.0 時代被廣泛地使用,其中一個重要的基礎是 JSON。JSON 已經成為最流行的數據交換格式,各大網站的 API 幾乎都支持它。它獨立於語言,相比 XML 它更加輕量。實際上 JSON 格式的數據就是一個 javascript 對象,所以我們經常看到前端通過 Ajax 獲取 JSON 格式的數據然後顯示在網頁上。

前端實現的精美界面,後端僅提供 JSON 格式數據

前端實現的精美界面,後端僅提供 JSON 格式數據

於是在前端眼裡,後端便退化為了數據源,實現完全的接口化。這種做法實際上是把後端的 View 剔除了,後端只負責輸出 JSON 數據給前端,前端收到後將 JSON 對象當作 Model 根據業務需要進行各種操作。這樣一個顯而易見的好處就是跨平台,除了 Web 頁面以及各種 App,第三方客戶端也能通過開放的接口獲取數據,形成良好的生態系統。

二、RESTful 接口

這就要求後端完全面向 API 設計,即使是 Web 版,也調用標準 OpenAPI 接口實現。REST 是目前大量 Web 2.0 網站使用的一種架構方案,同時它也是一種把世間一切看作無狀態對象的思維模式。Web 上所有的東西(頁面、圖像等)本質上都是資源。一個 RESTful 的應用,包含了 GET、POST、PUT、DELETE 這四種 HTTP Verb 標準定義的語義操作,直接對應了後端對數據的增刪改查。

GET    /articles       列表
GET    /articles/123   查看
POST   /articles       創建
PUT    /articles/123   更新
DELETE /articles/123   刪除

在這種模式下,如何設計資源的 URL 就顯得很重要了。RESTful 的世界觀認為 URL 中不需要動詞,因為所有的動作都可以抽象為 GET、POST、PUT、DELETE。簡單的就是美的,Keep the simple things simple。優秀的 API 通常還會有一些通用的約定,例如使用複數名詞,把複雜的參數放於 ? 號後面。更多關於 REST 的細節,強烈推薦來自 Apigee 的這篇演示文檔《RESTful API Design》

還有幾個知識點需要注意的——

  • GET 操作是安全的。所謂安全是指不管進行多少次操作,資源的狀態都不會改變。比如我用 GET 瀏覽文章,不管瀏覽多少次,那篇文章還在那,沒有變化。
  • PUT、DELETE 操作是冪等的。所謂冪等是指不管進行多少次操作,結果都一樣。比如我用 PUT 修改一篇文章,然後在做同樣的操作,每次操作後的結果並沒有不同,DELETE 也是一樣。
  • POST 操作既不是安全的,也不是冪等的,比如常見的POST重複加載問題:當我們多次發出同樣的POST請求後,其結果是創建出了若干的資源。

在 PHP 中,可以使用全局變量 $_SERVER['REQUEST_METHOD'] 判斷請求的方法,而且通常情況下都是用 file_get_contents('php://input') 輸入流 來獲取用戶輸入,不再使用 $_GET$_POST。各大 PHP 框架都對此進行了封裝以支援 RESTful 風格的 API 開發,例如在 Yii Framework 中,我們可以這樣定義路由

'urlManager'=>array(
	array('<controller>/index','pattern'=>'api/<controller>','verb'=>'GET','urlSuffix'=>'.json'),
	array('<controller>/show','pattern'=>'api/<controller>/<id\d+>','verb'=>'GET','urlSuffix'=>'.json'),
	array('<controller>/create','pattern'=>'api/<controller>','verb'=>'POST'),
	array('<controller>/update','pattern'=>'api/<controller>/<id\d+>','verb'=>'PUT'),
	array('<controller>/delete','pattern'=>'api/<controller>/<id\d+>','verb'=>'DELETE'),
),

三、前端 MVC 框架

前面已經說到,前端獲取 JSON 數據作為 Model,那麼 MVC 中的 View 和 Controller 又各自在前端扮演什麼角色呢?這就需要一套完整的框架作為解決方案了。現在市面上流行的前端 MVC 框架大概有下面幾種

  • Backbone.js. 應該是比較早出現的一個框架了,風靡於 Ruby on Rails 社區,包括 LinkedIn, Hulu, WordPress.com, Foursquare, Bitbucket, Disqus, Groupon, Basecamp, Pandora 以及國內的豆瓣,雪球,很多網站都使用了它,加上有 37signal 的背景,可謂是頗有知名度。它比較輕量,性能不錯,但正因為如此導致它缺失了很多前端需要的重要組件,你必須自己寫很多代碼來實現,隨着應用越來越複雜,要在更深層次嵌入視圖,惡夢 開始了……另外我對它主頁的文檔展現形式有點不爽,一個腦袋裡從來沒有前端 MVC 概念的人去讀,完全不知所云。
  • Knockout. 一個很強大的 MVVM 框架,如果你是 .NET 開發者你會很熟悉這種做法。它實現了 DOM 元素和 JS model 之間的雙向綁定,也就是說你在表單中的每一個輸入,都會實時更新到 model 里,最後提交表單也就等同於更新 model 的動作,一切很順暢。官方主頁上的例子也很容易理解。
  • AngularJS. 來自 Google,項目主頁直接就是 demo,讓你直接快速上手大呼過癮。乍一看讓人覺得很簡單,不過進了門之後你會發現後面的路還很長。它製造了很多概念,對於前端來講可以說是醍醐灌頂,比如它把 unix 里的 | (管道)搬到了前端……一開始我發現 AngularJS 和 Knockout 一樣在 HTML 中寫私有屬性立即就否決了它,後來發現原來它也支持 HTML5 標準的 data-* 寫法,於是又重新愛上了它。如果你習慣 Twitter Bootstrap 的應用方式我想你也會喜歡它的。
  • Ember.js. 比較有前途的一個框架,模板很好用,開發效率首屈一指。它有很多強制性約束,可以幫你自動完成很多事情。相比 Angular 上手可能要難一點,Angular 一開始不需要這麼費勁也能做一些讓人興奮不已的事兒,而 Ember 缺少這種前期興奮點。另外最令人不爽的是 Ember 的體積,min+gzip 壓縮之後還有 55K,太龐大了。
  • Batman.js. 適合 RoR 開發,沒怎麼用過。看上去和 Knockout.js 很像,提供了自動生成代碼的一些工具。整個庫壓縮後 40K 也比較大。
  • CanJS. 也沒用過,社區規模小。
  • Spine.js. 沒用過。輕量級。

那麼,到底該選哪個框架呢?我的建議是選一個項目,去看一下各個框架的實現,誰的代碼量少,誰的結構清晰,誰的實現方式讓你感覺比較爽,自然就有答案了。這不,在 Github 上早已經有國際友人分別用各種框架實現了經典的 todo 應用,方便大家比較。就我個人而言,我選擇了 AngularJS,用 AngularJS 代替 Backbone,代碼減少了一半。雖然性能可能有點問題,但面向未來嘛,瀏覽器會越來越強大的。圖靈社區 有一篇各種框架的詳細比較,推薦一讀。

四、AngularJS

AngularJS 的社區很活躍,開發迭代的速度也很快,畢竟是來自 Google,他們家著名的 CDN 都有收錄 AngularJS。在 AngularJS 中原生提供了 RESTful 的操作接口,調用形式和 jQuery 的 ajax 相關 API 類似

$http.get('/someUrl').success(successCallback);
$http.post('/someUrl', data).success(successCallback);

完整的調用方式列表包括——

  • $http.get
  • $http.head
  • $http.post
  • $http.put
  • $http.delete

這樣就能直接從瀏覽器發送標準的 HTTP 頭,配合後端的 RESTful 接口,非常方便。

在剛剛過去的 2013 Google I/O 大會上,AngularJS 的開發者對框架做了 介紹和演示。目前 AngularJS 的文檔可能還不夠完美,你可能會多花一點時間。但是相信我,這是值得的。當你熟悉了整個框架的設計,開發效率會有質的飛躍。

另外還有一些暗坑,例如通過 AngularJS 以外的 js 代碼(eg.第三方 jQuery 插件)對 AngularJS 的 model 進行操作(更改表單 field 值),需要手動調用 $apply 才能將新的值真正賦予 model,或者需要單獨寫 directive 來實現自動綁定。我另外寫了一篇文章介紹我使用 AngularJS 的心得

後記

我現在深受 New Twitter 的影響,傾向於把儘可能多的邏輯放到客戶端去做。Twitter 將 http://twitter.com/username 格式的 URL 統統都改成了 http://twitter.com/#!/username,因為瀏覽器的 HTTP 請求中並不包括 # 後面的內容,由此得知用戶內容都是 Ajax 方式生成的,頁面需要進行兩次抓取,第一次是 html 網頁(模板),第二次才是用戶的發言內容。Web 網頁和各種 app 客戶端實現了共享同一個 RESTful 接口,這正是我所推崇的方式。在前端 MVC 的幫助下,數據和 UI 雙向綁定,對頁面元素的操作也更為便捷了。

參考鏈接: