標籤:
web app簡介
web app其實不算是什麼新鮮的東西,相比於傳統的web和傳統的app,web app這種web和app相結合的產物有的優點如下:
1. 開發上web app更有便捷性,ios開發一上來需要安裝一堆東西,android開發也差不多,另外web app的學習成本要比平台用戶端開發要低些,至少你不用去招聘ios和android程式員。只要具備基礎web開發能力的人都可以比較快上手。
2. 部署方便,在很多情況下,部署一個單頁web app只需要一個index.html分頁檔作為容器和一個前端資源打包檔案(一般叫bundle.js)即可,然後把index.html放在自己伺服器項目路徑下,在其中引入bundle.js,至於bundle.js則可以放在CDN上,更新web app就等於是上傳並重新整理CDN緩衝。這樣一來前端部署極其簡單,基本上不需要SSH到伺服器去更換檔案,也可以避免自己的伺服器傳輸比較耗費頻寬的前端資源檔。
3. 單頁web app如果技術選型得當,開發和維護成本都相對比較低。
4. 可以適應更多環境。
凡事都有利弊,web app也有不盡如人意的地方,web app的主要缺點如下:
1. 效能上不如原生app,這個不用多說,基本是不可改變的事實。
2. 暫時還沒想到其他的。
前期準備
首先要進行技術選型,根據作者的經曆,我選擇的是react+flux,flux是一種資料流的架構方式,嚴格來說它並不是某一種特定的實現。比較常用的實現有facebook官方的flux實現,還有一些第三方實現(比如redux)。要注意的是,flux的具體實現基本不會影響到我們的項目開發,具體選擇哪個實現就看你的喜好了(當然最好不要中途再做改變:D)。
那麼就要來簡單介紹一下react是什麼,react可以說是一個改變前端生態系統的發明,傳統web開發中,我們以頁面為單位來設計模組,如果有多個頁面都用到了某個功能,比如一個列表,那麼就要重複地寫HTML和JS實現它,代碼抽象程度很低,冗餘度很高,也不利於後期維護。react推出了UI組件的概念,讓web前端開發人員可以封裝UI組件用於複用。
flux這種資料流架構思想其實也不是什麼新東西,但是真正在web前端大規模使用也是在開發人員使用react+flux之後的事情。flux制定了一些web前端資料擷取和分發的規則,雖然剛開始看上去比較複雜,但是一旦你理解了它的思想,其實很簡單,而且對於維護一個web app來說,react+flux可以說是相當不錯的組合。
設計一個web app具體是在設計什嗎?
剛才談到了react+flux,其實UI組件的封裝和資料流的架構,它們都幫開發人員規定好了,我們需要做的就是去好好運用它,那麼還有什麼可設計的呢?
還是有的,而且不少。從技術角度來說,web app和ios app、android app這些原生app在技術設計上有很多共通之處:
1. 頁面生命週期管理
2. 公用函數的設計
3. 局部/全域事件和通知
4. UI組件API設計
5. 常量定義
6. 網路請求
...
web app也具備一些原生app所沒有或不一樣的特性,例如app路由、JS(ES5/ES6差異)、使用/重新整理CDN緩衝、前端資源打包、快速部署等。
react+flux是怎麼工作的
由於本篇文章並不是react和flux的教程,所以只會大致介紹一下它們的工作方式。
下面是官方給出的一個flux工作流程圖:
詳細版:
簡單解釋一下flux的工作流程:
在第一張圖中,有兩種流程:
1. Action->Dispatcher->Store->View
2. View->Action->Dispatcher->Store->View
在Action->Dispatcher->Store->View中,可以通過調用Action中的方法來執行一項操作,這個操作可以是向伺服器請求資料,或僅僅在本地改變資料,操作完成後,Action會通知Dispatcher,然後由後者來指派動作和資料。在Store中,事先註冊好對各個類型事件的回呼函數,當Store接收到Dispatcher分發來的事件和資料時,就執行一些更新操作。另外View可以對Store註冊監聽器,一但Store中的資料有變化,會立即執行View預先設定好的監聽器回呼函數,這一般會是一個更新View的操作,這相當於一個發布-訂閱模式。
在View->Action->Dispatcher->Store->View中,實際上是說指使用者和View之間的互動導致資料變更(不管是請求伺服器還是本機資料改變),其他動作和Action->Dispatcher->Store->View基本一樣。
光看這些是十分抽象的,如果沒有深入去看一個demo或者自己實現一個項目,確實有點不好理解。我將在後續介紹flux和react。
本篇中react+flux基本介紹到這。下面要談談具體設計。
具體設計
一個web app無非就是顛來倒去地做以下幾件事:
1. 調用網路API
2. 展示頁面
3. 資料本機存放區(這裡一般指非持久化的那種,這和原生app有所不同)
4. 接受使用者輸入並反饋
作為技術人員,我們首先要明確幾點:
1. 明確地知道業務放需要什麼。
2. 劃分功能模組。
3. 弄清楚各個問題之間的依賴關係,制定模組之間的通訊規範。
4. 適當考慮項目未來走向,對架構設計留有餘地。
5. 分析風險。
6. 考慮如何解決依賴關係中最基礎的部分,先實現基礎模組(或者至少你要先對此有個大致的設計),不斷在此基礎上完善整個架構。這部分開發人員會花費比較大的精力去做,因為這影響到整個項目未來的幾乎所有事情。同時在這個過程中不斷審視架構是否合理,及時調整。
7. 單元測試,效能測試(如果項目需要且有時間的話)。
專案檔結構
好的開發習慣其中一個就是要制定清晰的專案檔結構,並且從始至終保持下去。
適當的文檔描述
如果可能的話,適當寫一些協助性的架構文檔,用簡潔明確的詞語傳達你想要表達的,讓後來的程式員可以快速上手。
思路和方法同一,不搞多元化
在一個項目中,對同一類事情應該有一個統一的處理方法,包括代碼風格、變數和方法的命名規範、調用規範、流程規範等,事先制定出來,並且要求所有人都要遵守。
盡量少的橫向依賴,盡量減少跨層訪問,降低模組間耦合度
這部分內容react+flux已經幫我們做了很大一部分。
對業務方該限制的地方有明確的限制,該靈活的地方要給業務方創造靈活實現的條件
可以通過良好的設計來保證這一點。
接下來會對劃分功能模組、模組間通訊規範、解決依賴關係這幾個方面進行說明。
功能模組的劃分
在react+flux的項目中,不談具體業務的情況下,有幾個大的基礎模組是一定要考慮的:
1. 展示模組
2. 網路請求模組
3. 本機存放區模組
4. 路由模組
5. 公用模組
1. 展示模組
這是使用者能直接看到的東西,我們用react封裝各個UI組件提供出來,也可以引入第三方UI組件,這本身已經是一種進步,讓我們可以在web前端“面向組件編程”,因此對UI組件的處理就尤為關鍵。ES6文法下,我們可以用extends react.Component來建立一個UI組件,然後在組件“類”中寫初始化方法、渲染方法、生命週期函數、事件回調等方法,然後把它作為一個整體提供出去,這裡就涉及到UI組件API的設計,UI組件可以接受屬性值,這些屬性應該儘可能的少和命名清晰、簡單,保持簡潔性很有必要。另外組件的展示離不開CSS和一些資源檔,作為一種封裝,把CSS、圖片等資源檔一併放在這個UI組件的檔案夾下也是很有必要的。
2. 網路請求模組
web app網路請求全靠ajax,在和伺服器互動時,應該和服務端約定好返回資料的格式,如錯誤碼的含義、出錯資訊、詳細的資料格式等,並且很有必要在web app端做一層封裝,比如封裝出一個request模組,在伺服器返回資料後首先解析返回資料,如果出錯就報錯,成功就執行使用者回呼函數等。這部分作為整個項目對外的介面應該考慮到所有可能的網路情況:伺服器致命錯誤、普通錯誤、成功、逾時、無網路等。
3. 本機存放區模組
這部分主要交給flux處理,我們需要做的就是設計本機資料的結構,使其盡量合理並適應多種應用情境。
4.路由模組
react+flux的單頁web app一般採用react-router作為路由,這可以省下你不少時間和精力,react-router是一個非常成熟和優秀的路由模組。
5. 公用模組
公用模組一般包括但不僅限於:公用函數、helper、常量定義、應用層級的功能(如展示loading框、警告框、確認框這些)。這部分功能也很重要,比如loading框,我們在發起網路請求時會展示它,資料返回時它會消失,那麼這個框的出現就與上面說到的網路模組有關係,警告框和確認框也是常用的東西,這些組件都可應該在app層面上進行設計和整合,而不應該放在各個UI組件內部,因為這個是一個app中的通用功能。
模組間通訊規範
在react+flux中,使用一種單向資料流的方式來分發資料,這就讓整個資料走向非常清楚,我們的web app模組間通訊規範就是根據這個單向資料流的思想來的。
解決依賴關係
react+flux中處理依賴關係時,用的比較多的方式無非3種:顯式引入、基於事件(發布-訂閱模式)、回呼函數。
在要向模組中引入其他模組時(import),使用顯式引入,這種依賴關係最強也最明顯。如果是依賴關係沒有那麼強,可以考慮用後面兩種,這有助於代碼的簡介和模組解耦。
基於事件(發布-訂閱模式),舉個簡單的例子,flux中當Store中的資料變化時,要通知相對應的View更新頁面,典型的處理方式是讓Store成為一個EventEmitter,同時View對該Store addChangeListener,即成為它的訂閱者,當Store改變時會自動調用該View的監聽回調,讓View更新介面。
基於回呼函數,有一個非常典型的用例,在設計通用的警告框和確認框組件時,有時我們需要在使用者點擊“確定”和“取消”按鈕時做一些事情,當然也可能什麼也不做。這時候我們不要忘了JS中函數是一等公民這件事,我們可以把事件處理函數傳遞給警告框和確認框組件,這樣就很巧妙的解決了跨組件、跨模組通訊而不會使模組過於耦合了。
如何設計和實現一個web app