關于框架和庫
jQuery 和 Backbone 的區(qū)別?
jQuery 通常是作為工具(或工具的倉庫)來用的,用 jQuery 是為了更方便,代碼更短、更簡單。
Backbone 則是體現(xiàn)了一種構建 Web 頁面/程序的思想,將應用程序進行分層,數(shù)據(jù)操作是一個層面,UI/視圖是一個層面。數(shù)據(jù)層的代碼不需要知道UI/視圖的存在,不關心樣式展現(xiàn)、界面交互的細節(jié);視圖層的代碼不關心數(shù)據(jù)是如何獲取、處理的,關系如何展現(xiàn)這些數(shù)據(jù),并將用戶交互操作轉交給數(shù)據(jù)層進行處理,而在數(shù)據(jù)發(fā)生變更時負責更新頁面。
作為框架的 Backbone

相對于庫,框架給出了一個應用程序大體架構,對代碼如何按照職能進行分層、分塊給出了建議/規(guī)定。開發(fā)新的程序時,開發(fā)者要遵循框架的各項原則編寫各部分代碼。
例如,對于 Backbone,如果我要從后臺請求數(shù)據(jù),這部分代碼我會放到 Model 或 Collection(其實是 Model 的集合)中,而響應用戶對按鈕點擊的代碼則放到 View 中。如果在 View 中我編寫了發(fā)送 Ajax 請求的代碼,通常來說是不好的模式(反模式)。
框架甚至可以讓開發(fā)者只負責“填充代碼”,由框架來調用開發(fā)者提供的代碼從而實現(xiàn)程序的運行。而對于庫,則是開發(fā)者來主動調用庫。框架的這種特性,稱為“控制反轉”(IOC)。不過對于 Backbone,開發(fā)者還是需要自己干很多事情,并沒有一種 Backbone 接管了程序的運行的感覺,如果想體驗這種感覺,AngularJS 應該比較像。
我理解的 Backbone
注意上圖(Models and Views),數(shù)據(jù)層(Model)有數(shù)據(jù)變更了,但并不知道關于視圖(View)的細節(jié),視圖如何根據(jù)變化后的數(shù)據(jù)更新頁面呢?
這里涉及到數(shù)據(jù)是如何流動的。
在 Backbone 中,這個比較簡單,和上圖類似,Model -> View。不過 View 實際上還會修改數(shù)據(jù),View -> Model。當然,從“可視性”上來看,Model 看不到 View,View 看得見 Model。View 通過監(jiān)聽 Model 的事件來知曉 Model 發(fā)生的變化。Model 在自身數(shù)據(jù)改變后,只需要觸發(fā)相應的事件來通知 View 即可,但這是 View 主動發(fā)起的監(jiān)聽,Model 并不知道是誰在監(jiān)聽。
查看 Backbone 的源碼,第一大部分即是 Event 系統(tǒng)的定義。無論是 Backbone.Model, Backbone.View 還是 Backbone.Collection 都繼承了 Event,也就是都有發(fā)布事件的能力。最主要的用途應該就是 Model 在數(shù)據(jù)變化時通知 View 的這種情況了。
所以,我理解的 Backbone 主要是三方面:
- 事件機制
- 數(shù)據(jù)層 Model
- 視圖層 View
至于 Backbone.Collection 和 Backbone.Router,都是工具嘛。
我理解的 React
再來看 React,和 Backbone 這種 MV* 框架的最大區(qū)別在于:React 并非是遵循 MVC 架構設計出來的!
在我看來,React 要解決的是快速開發(fā)可復用的 UI 組件的問題。從這個角度來看,React 甚至不算是完成的框架。Facebook 還提供了 Flux,算是對 React 的補充。Flux 是一個完成的應用架構的理念,React 在其中是作為 View 存在的。
來看 Flux 的結構和數(shù)據(jù)流圖:

Flux 被設計為單向的數(shù)據(jù)流,Store 中的數(shù)據(jù),可以被 View 獲取,但 View 并不直接對 Store 進行操作。View 接收的用戶交互,可能會導致數(shù)據(jù)變更,此時創(chuàng)建一個 Action。各種類型的 Action 匯總到一個全局的 Dispatcher 中,由 Dispatcher 再進一步轉發(fā)給關心的 Store,Store 如果變更了,View 會通過事件獲得通知,從而進一步更新界面顯示。
繞這么一圈,有點蛋疼吧?
不過 Facebook 在相關文檔中給出了這樣設計的原因和優(yōu)勢,我理解的一個主要的原因應該是單向的數(shù)據(jù)流 —— 簡單!
將 React 放在 Flux 的提供的架構里來看,就比較容易理解 React 的特性了。React 被設計為整體渲染的方式,也就是說,如果一部分數(shù)據(jù)發(fā)送變化,也不會單獨渲染頁面上的一部分,而是直接調用渲染函數(shù)全部刷新。
這樣做的話固然簡單了很多,但是性能豈不是很差?
React 的解決方案是:別怕,不是真的重新渲染一般,底層會對比新生成的 DOM 和已有的 DOM 的差別,智能地更新改變的部分。所以在 React 中有 Virtual DOM 的存在,直接操作的并不是真實的 DOM。這么一來,代碼簡單了,性能問題據(jù)說也不用擔心。
React 的 UI 組件中,不能修改獲取的數(shù)據(jù),這個特性從 Flux 里可以看出,F(xiàn)acebook 希望數(shù)據(jù)是單向流動的嘛,所以 View 中的數(shù)據(jù)視為不可修改的。想修改?創(chuàng)建一個 Action 嘛。
其實在 Flux 工程中,只是實現(xiàn)了 Dispatcher,對于 Action 和 Store 并沒有缺省的實現(xiàn)。Action,其實就是一個結構化數(shù)據(jù)對象,調用 Dispatcher 時傳入。從 Flux 項目的示例應用 TodoMVC 中可以看到,Action 的代碼,準確來說是 Action Creator,用于創(chuàng)建 Action 發(fā)送給 Dispatcher。而 Store,F(xiàn)acebook 說只要實現(xiàn)了事件訂閱、發(fā)布就行,示例應用是采用了 Node.js 的 EventEmitter,也可以用其他的事件模型替換。
有一個問題:在各層面與后臺產生聯(lián)系,獲取、更新數(shù)據(jù)呢?
View,也就是 React 的部分應該要排除,在 Flux 的體系里,它不應該操作數(shù)據(jù)。Dispatcher 其實只管轉發(fā) Action 給 Store 處理,本身不處理數(shù)據(jù)。所以是 Action 和 Store 中的一個。
Action 本身只是數(shù)據(jù),或者消息數(shù)據(jù),如果攜帶有數(shù)據(jù),應該是創(chuàng)建 Action 的模塊來請求數(shù)據(jù)。
Store 的話如果干這件事就很自然了,請求數(shù)據(jù),更新自身,觸發(fā)事件,View 響應....
Facebook 推薦,或者說設計的模式的怎樣的呢?
查看 Flux 示例應用 Chat Client,答案是:都不是!
有一個 utils/ChatWebAPIUtils.js 來模擬與服務器的交互(實際是使用 LocalStorage 存取數(shù)據(jù)),獲取新的數(shù)據(jù)后,通過 Action 發(fā)布,看代碼:
// flux-master\examples\flux-chat\js\utils\ChatWebAPIUtils.js
// line 50
setTimeout(function() {
ChatServerActionCreators.receiveCreatedMessage(createdMessage);
}, 0);
所以,我揣測 Facebook 推薦的方式,哪里也不放!把與服務器交互的代碼單獨寫到一個模塊里面,供其他模塊調用。初始獲取數(shù)據(jù)的操作應該是在 app.js 這樣的入口模塊中,更新方面的調用應該還是會在 Store 里面吧。
其他
Backbone 是實際工作中用過的,不過是自己琢磨著用,是否規(guī)范就不得而知啦。對于 Backbone 的理解當然也是我自己琢磨的。
React 并未在實際工作中,說實話也只是這兩天花時間學習了下,感覺自己算算入門了。在學習 React 的時候有很多疑問,后來在看到 Flux 之后才算解惑了,壓根 React 就沒想著獨擋一門,作為完整的框架使用,遵循 Flux 的架構的話就比較完整了。