讓咱們先來看幾個站點:css
coding(https://coding.net/)html
teambition(https://www.teambition.com/)前端
cloud9(https://c9.io/)
node
注意這幾個站點的相同點。那就是在瀏覽器中,作了原先「應當」在client作的事情。git
它們的界面切換很是流暢,響應很是迅速,跟傳統的網頁明顯不同,它們是什麼呢?這就是單頁Web應用。github
所謂單頁應用。指的是在一個頁面上集成多種功能。甚至整個系統就僅僅有一個頁面,所有的業務功能都是它的子模塊,經過特定的方式掛接到主界面上。web
它是AJAX技術的進一步昇華。把AJAX的無刷新機制發揮到極致,所以能造就與桌面程序媲美的流暢用戶體驗。後端
事實上單頁應用咱們並不陌生,很是多人寫過ExtJS的項目。用它實現的系統。很是自然的就已是單頁的了。也有人用jQuery或者其它框架實現過類似的東西。設計模式
用各類JS框架。甚至不用框架。都是可以實現單頁應用的。它僅僅是一種理念。有些框架適用於開發這種系統。假設使用它們,可以獲得很是多便利。瀏覽器
ExtJS可以稱爲第一代單頁應用框架的典型,它封裝了各類UI組件。用戶主要使用JavaScript來完畢整個前端部分,甚至包含佈局。
隨着功能逐漸添加,ExtJS的體積也逐漸增大。即便用於內部系統的開發。有時候也顯得笨重了,更不用說開發以上這類執行在互聯網上的系統。
jQuery因爲偏重DOM操做。它的插件體系又比較鬆散。因此比ExtJS這個體系更適合開發在公網執行的單頁系統,整個解決方式會相對照較輕量、靈活。
但因爲jQuery主要面向上層操做,它對代碼的組織是缺少約束的。如何在代碼急劇膨脹的狀況下控制每個模塊的內聚性。並且適當在模塊之間產生數據傳遞與共享。就成爲了一種有挑戰的事情。
爲了解決單頁應用規模增大時候的代碼邏輯問題,出現了很多MV*框架。他們的基本思路都是在JS層建立模塊分層和通訊機制。
有的是MVC,有的是MVP。有的是MVVM。並且,它們差點兒都在這些模式上產生了變異。以適應前端開發的特色。
這類框架包含Backbone。Knockout,AngularJS,Avalon等。
這些在前端作分層的框架推進了代碼的組件化,所謂組件化,在傳統的Web產品中,不少其它的指UI組件,但事實上組件是一個普遍概念。傳統Web產品中UI組件佔比高的緣由是它的厚度不足,隨着client代碼比例的添加,至關一部分的業務邏輯也前端化,由此催生了很是多非界面型組件的出現。
分層帶來的一個優點是,每層的職責更專注了,由此,可以對其做單元測試的覆蓋,以保證其質量。
傳統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上。因爲它也是單「頁面」的產品模式。需要面對相同的問題。
當產品狀態複雜到必定程度的時候,路由又變得很是難應用了,因爲狀態的管理極其麻煩,比方開始的時候咱們演示的c9.io在線IDE,它就無法把狀態相應到url上。
在單頁應用的運做機制中。緩存是一個很是重要的環節。
因爲這類系統的前端部分差點兒全是靜態文件。因此它可以有機會利用瀏覽器的緩存機制,而比方動態載入的界面模板,也全然可以作一些本身定義的緩存機制。在非首次的請求中直接取緩存的版本號,以加快載入速度。
甚至,也出現了一些方案,在動態載入JavaScript代碼的同一時候,把它們也緩存起來。比方Addy Osmani的這個basket.js。就利用了HTML5 localStorage做了js和css文件的緩存。
在單頁產品中,業務代碼也常常會需要跟本地存儲打交道,存儲一些暫時數據。可以使用localStorage或者localStorageDB來簡化本身的業務代碼。
傳統的Web產品一般使用JSONP或者AJAX這種方式與服務端通訊,但在單頁Web應用中。有很是大一部分採用WebSocket這種實時通信方式。
WebSocket與傳統基於HTTP的通訊機制相比,有很是大的優點。
它可以讓服務端很是便利地使用反向推送,前端僅僅響應確實產生業務數據的事件。下降一遍又一遍無心義的AJAX輪詢。
因爲WebSocket僅僅在比較先進的瀏覽器上被支持,有一些庫提供了在不一樣瀏覽器中的兼容方案。比方socket.io,它在不支持WebSocket的瀏覽器上會降級成使用AJAX或JSONP等方式,對業務代碼全然透明、兼容。
傳統的Web頁面一般是不需要考慮內存的管理的。因爲用戶的停留時間相對少,即便出現內存泄漏。可能很是快就被刷新頁面之類的操做沖掉了,但單頁應用是不一樣的。它的用戶很是可能會把它開一成天。所以。咱們需要對當中的DOM操做、網絡鏈接等部分格外當心。
在單頁應用中。因爲頁面的集成度高。所有頁面彙集到同一做用域,樣式的規劃也變得重要了。
樣式規劃主要是幾個方面:
這裏面主要包含瀏覽器樣式的重設、全局字體的設置、佈局的基本約定和響應式支持。
這裏面是兩個層面的規劃,首先是各類界面組件及其子元素的樣式。其次是一些修飾樣式。組件樣式應當儘可能下降互相依賴,各組件的樣式贊成冗餘。
傳統Web頁面的特色是元素多。但是層次少,單頁應用會有些不一樣。
在單頁應用中,需要提早爲各類UI組件規劃堆疊次序。也就是z-index,比方說,咱們可能會有各類彈出對話框,浮動層,它們可能組合成各類堆疊狀態。新的對話框的z-index需要比舊的高,才幹確保蓋在它上面。諸如此類,都需要咱們對這些可能的遮蓋做規劃。那麼,如何去規劃呢?
瞭解通訊知識的人,應當會知道,不一樣的頻率段被劃分給不一樣的通訊方式使用,在一些國家,領空的使用也是有劃分的。咱們也可以用相同的方式來預先分段,不一樣類型的組件的z-index落到各自的區間。以免它們的衝突。
咱們在開始的時候提到,存在着很是多新型Web產品,使用單頁應用的方式構建,但實際上,這類產品不只僅存在於Web上。
點開Chrome商店,咱們會發現很是多離線應用。這些產品都可以算是單頁應用的體現。
除了各類瀏覽器插件。藉助node-webkit這種外殼平臺。咱們可以使用Web技術來構建本地應用,產品的主要部分仍然是咱們熟悉的單頁應用。
單頁應用的流行程度正在逐漸添加。你們假設關注了一些初創型互聯網企業。會發現當中很是大一部分的產品模式是單頁化的。這種模式能帶給用戶流暢的體驗,在開發階段。對JavaScript技能水平要求較高。
單頁應用開發過程當中,先後端是自然分離的,兩方以API爲分界。前端做爲服務的消費者,後端做爲服務的提供者。在此模式下,前端將會推進後端的服務化。
當後端再也不承擔模板渲染、輸出頁面這樣工做的狀況下。它可以更專一於所提供的API的實現,而在這種狀況下。Web前端與各類移動終端的地位對等,也逐漸使得後端API沒必要再爲每個端做差別化設計了。
在現在這個時代,咱們已經可以看到一種產品的出現了。那就是「無後端」的Web應用。
這是一種什麼東西呢?基於這種理念。你的產品很是可能僅僅需要本身編寫靜態Web頁面,在某種BaaS(Backend as a Service)雲平臺上定製服務端API和雲存儲,集成這個平臺提供的SDK,經過AJAX等方式與之打交道,實現註冊認證、社交、消息推送、實時通訊、雲存儲等功能。
咱們觀察一下這種模式,會發現先後端的部署已經全然分離了,前端代碼全然靜態化,這意味着可以把它們放置到CDN上,訪問將大大地加速。而服務端託管在BaaS雲上。開發人員也沒必要去關注一些部署方面的繁瑣細節。
假設你是一名創業者。正在作的是一種實時協同的單頁產品,可以在雲平臺上,高速定製後端服務。把絕大部分寶貴的時間花在開發產品自己上。
單頁應用最根本的缺陷就是不利於SEO,因爲界面的絕大部分都是動態生成的,因此搜索引擎很是不easy索引它。
一個產品想要單頁化。首先是它必須適合單頁的形態。
其次,在這個過程當中。對開發模式會產生一些變動,對開發技能也會有一些要求。
開發人員的JavaScript技能必須過關,同一時候需要對組件化、設計模式有所認識,他所面對的再也不是一個簡單的頁面,而是一個執行在瀏覽器環境中的桌面軟件。