所謂單頁應用,指的是在一個頁面上集成多種功能,甚至整個系統就只有一個頁面,全部的業務功能都是它的子模塊,經過特定的方式掛接到主界面上。它是AJAX技術的進一步昇華,把AJAX的無刷新機制發揮到極致,所以能造就與桌面程序媲美的流暢用戶體驗。
開發框架
ExtJS能夠稱爲第一代單頁應用框架的典型,它封裝了各類UI組件,用戶主要使用JavaScript來完成整個前端部分,甚至包括佈局。隨着功能逐漸增長,ExtJS的體積也逐漸增大,即便用於內部系統的開發,有時候也顯得笨重了,更不用說開發以上這類運行在互聯網上的系統。
jQuery因爲偏重DOM操做,它的插件體系又比較鬆散,因此比ExtJS這個體系更適合開發在公網運行的單頁系統,整個解決方案會相對比較輕量、靈活。
但因爲jQuery主要面向上層操做,它對代碼的組織是缺少約束的。如何在代碼急劇膨脹的狀況下控制每一個模塊的內聚性,而且適當在模塊之間產生數據傳遞與共享,就成爲了一種有挑戰的事情。
爲了解決單頁應用規模增大時候的代碼邏輯問題,出現了很多MV*框架,他們的基本思路都是在JS層建立模塊分層和通訊機制。有的是MVC,有的是MVP,有的是MVVM,並且,它們幾乎都在這些模式上產生了變異,以適應前端開發的特色。
這類框架包括Backbone,Knockout,AngularJS,Avalon等。
組件化
這些在前端作分層的框架推進了代碼的組件化,所謂組件化,在傳統的Web產品中,更多的指UI組件,但其實組件是一個普遍概念,傳統Web產品中UI組件佔比高的緣由是它的厚度不足,隨着客戶端代碼比例的增長,至關一部分的業務邏輯也前端化,由此催生了不少非界面型組件的出現。
分層帶來的一個優點是,每層的職責更專注了,由此,能夠對其做單元測試的覆蓋,以保證其質量。傳統UI層測試最頭疼的問題是UI層和邏輯混雜在一塊兒,好比每每會在遠程請求的回調中更改DOM,當引入分層以後,這些東西均可以分別被測試,而後再經過場景測試來保證總體流程。
代碼隔離
與開發傳統頁面型網站相比,實現單頁應用的過程當中,有一些比較值得特別關注的點。
從單頁應用的特色來看,它比頁面型網站更加依賴於JavaScript,而因爲頁面的單頁化,各類子功能的JavaScript代碼彙集到了同一個做用域,因此代碼的隔離、模塊化變得很重要。
在單頁應用中,頁面模板的使用是很廣泛的。不少框架內置了特定的模板,也有的框架須要引入第三方的模板。這種模板是界面片斷,咱們能夠把它們類比成JavaScript模塊,它們是另外一種類型的組件。
模板也同樣有隔離的須要。不隔離模板,會形成什麼問題呢?模板間的衝突主要存在於id屬性上,若是一個模板中包含固定的id,當它被批量渲染的時候,會形成同一個頁面的做用域中出現多個相同id的元素,產生不可預測的後果。所以,咱們須要在模板中避免使用id,若是有對DOM的訪問需求,應當經過其餘選擇器來完成。若是一個單頁應用的組件化程度很是高,極可能整個應用中都沒有元素id的使用。
代碼合併與加載策略
人們對於單頁系統的加載時間容忍度與Web頁面不一樣,若是說他們願意爲購物頁面的加載等待3秒,有可能會願意爲單頁應用的首次加載等待5-10秒,但在此以後,各類功能的使用應當都比較流暢,全部子功能頁面儘可能要在1-2秒時間內切換成功,不然他們就會感受這個系統很慢。
從這些特色來看,咱們能夠把更多的公共功能放到首次加載,以減少每次加載的載入量,有一些站點甚至把全部的界面和邏輯所有放到首頁加載,每次業務界面切換的時候,只產生數據請求,所以它的響應是很是迅速的,好比青雲的控制檯就是這麼作的。
一般在單頁應用中,無需像網站型產品同樣,爲了防止文件加載阻塞渲染,把js放到html後面加載,由於它的界面基本都是動態生成的。
當切換功能的時候,除了產生數據請求,還須要渲染界面,這個新渲染的界面部件通常是界面模板,它從哪裏來呢?來源無非是兩種,一種是即時請求,像請求數據那樣經過AJAX獲取過來,另外一種是內置於主界面的某些位置,好比script標籤或者不可見的textarea中,後者在切換功能的時候速度有優點,可是加劇了主頁面的負擔。
在傳統的頁面型網站中,頁面之間是互相隔離的,所以,若是在頁面間存在可複用的代碼,通常是提取成單獨的文件,而且可能會須要按照每一個頁面的需求去進行合併。單頁應用中,若是總的代碼量不大,能夠總體打包一次在首頁載入,若是大到必定規模,再做運行時加載,加載的粒度能夠搞得比較大,不一樣的塊之間沒有重複部分。
路由與狀態的管理
管理路由的目的是什麼呢?是爲了能減小用戶的導航成本。好比說咱們有一個功能,經歷過屢次導航菜單的點擊,才呈現出來。若是用戶想要把這個功能地址分享給別人,他怎麼才能作到呢?
傳統的頁面型產品是不存在這個問題的,由於它就是以頁面爲單位的,也有的時候,服務端路由處理了這一切。可是在單頁應用中,這成爲了問題,由於咱們只有一個頁面,界面上的各類功能區塊是動態生成的。因此咱們要經過對路由的管理,來實現這樣的功能。
具體的作法就是把產品功能劃分爲若干狀態,每一個狀態映射到相應的路由,而後經過pushState這樣的機制,動態解析路由,使之與功能界面匹配。
有了路由以後,咱們的單頁面產品就能夠前進後退,就像是在不一樣頁面之間同樣。
其實在Web產品以外,早就有了管理路由的技術方案,Adobe Flex中,就會把好比TabNavigator,甚至下拉框的選中狀態對應到url上,由於它也是單「頁面」的產品模式,須要面對一樣的問題。
緩存與本地存儲
在單頁應用的運做機制中,緩存是一個很重要的環節。
因爲這類系統的前端部分幾乎全是靜態文件,因此它可以有機會利用瀏覽器的緩存機制,而好比動態加載的界面模板,也徹底能夠作一些自定義的緩存機制,在非首次的請求中直接取緩存的版本,以加快加載速度。
甚至,也出現了一些方案,在動態加載JavaScript代碼的同時,把它們也緩存起來。好比Addy Osmani的這個basket.js,就利用了HTML5 localStorage做了js和css文件的緩存。
在單頁產品中,業務代碼也經常會須要跟本地存儲打交道,存儲一些臨時數據,可使用localStorage或者localStorageDB來簡化本身的業務代碼。
服務端通訊
傳統的Web產品一般使用JSONP或者AJAX這樣的方式與服務端通訊,但在單頁Web應用中,有很大一部分採用WebSocket這樣的實時通信方式。
WebSocket與傳統基於HTTP的通訊機制相比,有很大的優點。它可讓服務端很便利地使用反向推送,前端只響應確實產生業務數據的事件,減小一遍又一遍無心義的AJAX輪詢。
因爲WebSocket只在比較先進的瀏覽器上被支持,有一些庫提供了在不一樣瀏覽器中的兼容方案,好比http://socket.io,它在不支持WebSocket的瀏覽器上會降級成使用AJAX或JSONP等方式,對業務代碼徹底透明、兼容。
內存管理
傳統的Web頁面通常是不須要考慮內存的管理的,由於用戶的停留時間相對少,即便出現內存泄漏,可能很快就被刷新頁面之類的操做沖掉了,但單頁應用是不一樣的,它的用戶極可能會把它開一成天,所以,咱們須要對其中的DOM操做、網絡鏈接等部分格外當心。
樣式的規劃
樣式規劃主要是幾個方面:
基準樣式的分離
這裏面主要包括瀏覽器樣式的重設、全局字體的設置、佈局的基本約定和響應式支持。
組件樣式的劃分
這裏面是兩個層面的規劃,首先是各類界面組件及其子元素的樣式,其次是一些修飾樣式。組件樣式應當儘可能減小互相依賴,各組件的樣式容許冗餘。
堆疊次序的管理
傳統Web頁面的特色是元素多,可是層次少,單頁應用會有些不一樣。