如何設計和實現一個web app


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中函數是一等公民這件事,我們可以把事件處理函數傳遞給警告框和確認框組件,這樣就很巧妙的解決了跨組件、跨模塊通信而不會使模塊過於耦合了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM