小釵從事單頁相關的開發一年有餘,期間無比的推崇webapp的網站模式,也整理了不少移動開發的知識點,可是如今回過頭來看,webapp到底是好仍是很差真是一言難盡喲!javascript
webapp使用JavaScript修改頁面;緊接着再從服務器傳遞更多數據而後再修改頁面,如此循環。css
從性能的角度看,在現代瀏覽器中單頁面Web App已經可以和普通native應用程序相媲美,並且幾乎全部的操做系統都支持現代的瀏覽器。html
因此,不少人認爲webapp是HTML5流行過程當中最大的贏家,那麼他有哪些特定呢?前端
SPA(single page application),即單頁webapp,它具備如下優勢:html5
用戶體驗,對於內容的改動不須要加載整個頁面。這樣不會出現白頁狀況,頁面與頁面無縫切換,甚至帶有必定動畫效果。java
請求量少,請求內容無需服務器解析,對服務器壓力較小,消耗更少的帶寬,好比每次不須要接收完整的html結構,而只須要json數據。web
固然,單頁應用也不是完美無瑕的,他也具備如下問題:json
因爲歷史緣由,單頁應用對SEO支持不是太好,須要對SEO作特殊處理。瀏覽器
首次加載量過大,首屏加載慢,因此首屏須要作特殊處理。緩存
自己入門門檻就高,加之view編碼須要釋放資源,以避免heap值太高,對編碼人員的要求較高。
傳說中的webapp足以媲美native app,事實上這個足以還有很大的距離,小釵預計這個「足以」須要用2-3年時間填平,因此事實是什麼呢?
事實上移動端的webapp模式的網站不多不多,一淘半年前仍是,這兩天一看又變回來了,小釵雖然對webapp抱有信心,可是信心從何而來呢?
攜程webapp獨樹一幟,去哪兒ipad介入webapp,可是國內主流網站依舊是傳統網站,主要緣由不過有二:
① SEO
② 不想吃螃蟹
因此,攜程的webapp在國內,何其難得,說到這裏,我都要哭出來了......
孰優孰劣非是小釵能夠論斷,求穩,webapp不比傳統網站;求SEO,webapp須要其它解決方案;說垃圾收集,webapp須要本身釋放資源。
說體驗,webapp須要考慮首屏加載;說動畫,webapp要考慮低端手機,因此webapp還有很長一段路須要走!
小釵相信,如今的webapp效果不可媲美native app,總有一天,當webapp再也不制約於網絡、設備,那麼webapp的春天不會遠。
雖然說如此,現階段webapp也會有許多優化心得、奇技淫巧能夠拿出來講說的,這裏小釵作一次分享,但願能夠對webapp的同窗有所幫助。
前端優化分爲兩個切入點:網絡傳輸與DOM操做,而網絡傳輸是制約一個網站速度的主要因素。
網絡傳輸的優化要點是,零請求,無流量,其意是最大程度的減小請求數,下降請求量。
對webapp模式的應用來講,首屏加載慢是一個不可避免的問題,因此提高webapp首屏加載速度是提高總體網站速度的關鍵。
以上是一個網站首頁的加載時間,咱們分別取其150kb與30kb網速的加載速度,能夠看出會慢!若他是webapp,咱們能夠作一些優化
咱們應該避免頁面長時間白頁,這個時候便提出了fake頁的概念。頁面渲染只須要完整的HTML以及CSS,這個即是第一個優化點。
從數據請求數以及請求量來講,webapp首頁的響應應該比較慢,如果任由js加載完成再渲染頁面,用戶頗有可能失去耐心。
可是從DOMContentLoaded來看,首頁事實上頁面響應比較迅速,因此這個加載結束後頁面第一屏便渲染結束,而後再異步加載js,當js改變後再動態改變dom結構中的一些關鍵點
這個時候一個靜態HTML頁面,裝載首屏的基本內容,讓首頁快速顯示
而後js加載結束後會立刻從新渲染整個頁面,這個樣子,用戶就能夠很快的看到頁面響應,給用戶一個快的錯覺,給人感受快得多。
由webapp首頁來講,不可避免的使用的js文件較多,這些文件分爲兩類:
① 框架js-css
② 各個業務團隊js-css
因此能夠限定每一個業務團隊只會加載這四個文件,以最小下降請求數,這裏又涉及到並行加載,數量與容量有一個臨界值,如何取這個臨界值須要各位本身去實驗
雖然說圖片壓縮是沒必要說的事情,可是總會有些時候你會發現一些網站的圖片尺寸很大,這個須要處理,並且必須處理。
以框架庫爲例,除了核心包之外,不須要的UI或者功能庫能夠剔除,用到了再動態加載,減小首次加載量,這個一開始就得作好,作很差後期就很差改
以業務團隊爲例,首次加載的js與html模板會將經常使用的幾個頁面壓縮合並,其它頁面訪問時再請求,如果想提高首屏加載即可以只下載須要的頁面文件。
另外,如下兩點尤爲須要注意:
① 如果大家是要的仍是jQuery庫的話,能夠考慮換成zepto了
② 勿胡亂引用第三方庫,如果要引用必定是讀懂源碼的狀況下重寫使用之,這樣的好處是,吃得透,萬一有問題,能改,而不是沒辦法又換庫
該方案的原理與前面相似,咱們發送Ajax請求時候,應該緩存一些非實時數據,好比城市信息和經常使用聯繫人,可是咱們只能緩存非敏感信息,
產品搜索頁至列表頁的請求數據會緩存30s-60s,如果過時時間內用戶回到列表頁的話不會從新請求數據
這對服務器壓力,頁面響應皆是有利的,這個在30s內事實上意義不大,能夠減小一次請求。
另外,對於get和post的效率,曾經有人作過一次測試:
get100次平均耗時323ms;post100次平均耗時589ms,因此post方式是比get慢的,但post請求的優勢是安全,而且參數沒有長度限制。
是選擇post仍是選擇get,皆須要處理,避免截斷url,或者到處post。-
只顯示首屏頁面,其它內容須要時再加載,好比列表頁、圖片lazyload,皆須要作
DOM操做主要分爲頁面渲染與資源清理(heap控制),二者之間又相輔相成,如果DOM操做一塊處理很差,其產生的感受就再也不是慢,而是卡
因此DOM操做優化的主要目的就是消滅頁面卡的問題,這個在移動端尤其重要。
瀏覽器會解析三個東西:HTML、Javascript、CSS
瀏覽器首先會根據HTML生成DOM Tree,其次會根據CSS生成CSS Rule Tree,javascript能夠經過DOM API與CSS API操做DOM Tree與CSS Rule Tree,從而引發頁面變化。
瀏覽器解析結束會經過DOM Tree與CSS Rule Tree造成render tree,只有display不爲none的元素纔會造成render Tree,render Tree造成後瀏覽器會調用GUI繪製頁面,在此以前作的一件事情即是layout或者說reflow。上面的描述簡單而言能夠分爲如下流程:
l 生成DOM樹
l 計算CSS樣式
l 構建render tree
l reflow,定位元素位置大小
l 繪製頁面
在這個過程當中,如果javascript動態改變DOM Tree便會引發reflow
頁面中的元素改變,只要不影響尺寸,好比只是顏色改變只會引發repaint不會引發迴流
不然,reflow不可避免,這個時候便須要從新計算造成render Tree
reflow分爲局部迴流與全局迴流,會影響下面的,不會影響上面的元素
reflow耗用的系統資源較大,DOM Tree中受到影響的節點皆會reflow,而後影響其子節點最壞的狀況是全部節點reflow,該問題引起的現象即是低性能的電腦風扇不停的轉,手機變得很熱,而且很是耗電,如下操做可能引發reflow
l 操做dom結構
l 動畫
l DOM樣式修改
l 獲取元素尺寸的API
static元素處於文檔流中,其渲染速度是最快的,咱們作過一個測試:
100個absolute元素與100個static元素渲染時差在0.01-0.007ms
100000個元素渲染差距便增至30ms左右,這個微小的時差在移動端變得尤其明顯,好比:
小米/三星手機(1000左右),便存在明顯的渲染問題,具體表現爲:
l 定位元素在手機上不能顯示。
l 定位元素動畫效果失效。
以上問題即是UI渲染失效多致使,最好的解決方案是減小使用定位元素,不然只能引發強烈reflow才能解決。
另外,產品常常會有fixed的相關需求,好比支付按鈕一直出如今低端,這個需求會形成兩個問題:
l fixed元素遭遇文本框時失效,可能會飄到頁面中間阻擋輸入
l 影響效率
問題一緣由與移動端的實現有關,暫時沒有完美的解決方案,問題二便與渲染直接關聯
滾屏時,頁面上全部的像素會跟着滾動,顯卡對全屏幕上下移動的處理很快,可是如果出現一個fixed元素或者有元素不跟着一塊兒滾動,那麼滾動對手機瀏覽器來講就是一個負擔,這種滾動的性能甚至體如今了iphone 4s,由於滾動可能會形成reflow,這個現象體如今:
使用absolute配合javascript模擬fixed效果時,會有斷片的效果,該問題在iphone5s便不會出現這個問題。
固然,咱們不能忽略產品的需求,fixed類需求應該在技術上獲得解決,還用戶一個良好的體驗。
虛擬鍵盤致使fixed元素錯位
fixed元素必定會伴隨虛擬鍵盤的出現,可是虛擬鍵盤只是「貼」在了viewport上,表面上不會對dom產生「任何」影響,可是這個時候fixed元素表現卻變得怪異起來,會錯位。
應用層面解決問題方案是,虛擬鍵盤彈出時將fixed元素設置爲static,虛擬鍵盤消失時候設置回來。
因爲虛擬鍵盤出現並未拋出事件,而檢測scroll或者resize事件,皆會有必定延遲,會出現閃爍現象,因此現有最好的方案是setinterval定時器監控當前獲取焦點元素是否爲文本元素,如果是的話便須要處理,如此即可解決fixed元素錯誤問題。
fixed元素滑動慣性平滑度
咱們經常遇到這種產品需求,tab標籤欄開始固定,當滾動向下超過該標籤欄後便會變成fixed元素,一直出如今頭部,這樣的需求在電腦上沒有問題,可是在iPhone5s如下的手機經常會出現小範圍錯位或者快速移動大範圍錯位的問題。
這個時候咱們能夠引發reflow迫使瀏覽器重繪以解決這個問題,這裏推薦一個奇怪的hack寫法:同時設置三個image元素的src屬性,即可以全範圍解決該難題, 該方案被團隊證明並獲得應用。
//三圖片src,引起reflow,處理fixed方案慣性問題
var el = this.els.ctlc.find('img');
$(el[0]).attr("src", 'http://res.m.ctrip.com/html5/Content/images/144.png');
$(el[1]).attr("src", 'http://res.m.ctrip.com/html5/Content/images/144.png');
$(el[2]).attr("src", 'http://res.m.ctrip.com/html5/Content/images/144.png');
另外,上圖中的tab標籤下面的藍線具備動畫,可是在小米或者三星手機上可能不會移動,這個時候也能夠動態引發reflow解決這個BUG。
l CSS選擇器儘可能使用id與class,避免過分層疊
l 避免使用數值,好比:border: none不會引發渲染,而boder: 0會
l 動畫時候讓元素脫離文檔流,以避免致使大量reflow
l 避免逐條修改DOM樣式,改以className實現一樣功能
l 操做DOM時將display設置爲none,由於這種元素不會影響渲染,或者操做fragment對象取代操做顯示在頁面上的DOM
l 避免將獲取DOM樣式屬性的操做寫在循環中,可能引發重複reflow
首先,移動端的性能與PC端的性能徹底不在一個數量級上,好比,我哥作過一個測試,使用innerHTML繪製大段,以後想獲取HTML的ID節點,事實上是獲取不到的,這種問題在單頁模擬多頁,動態建立DOM會常常發生
var element = $('<div id = "test">...大量結構...</div>');
$(root).html(element)
$('#test) //爲空
這類問題匪夷所思,由於頁面UI渲染與DOM操做是互斥的,可是就算出現了這個問題,一個解決方案是使用settimeout,更好的方案是使用DOMNodeRemoved事件監控頁面DOM改變,將咱們的DOM操做回調放入以確保渲染結束。
以上問題只是爲了說明移動端的性能問題,這類性能問題會致使不少莫名其妙的問題,並且不少與渲染有關。可是這也從側面說明了移動端資源的緊缺,如果heap值過大,會致使操做出現卡的現象,更有甚者,會引發頁面假死直接退出。
webapp的模式,徹底依賴於瀏覽器的垃圾回收,基本就是做死,由於傳統頁面一旦刷新頁面整個資源徹底釋放,而webapp沒有刷新這類操做,只有一個狀態到兩一個狀態,不相關的內存會保留,資源必須手動釋放,或者說,框架必須提供垃圾釋放的機制。
這個由圖表heap值變化能夠清晰看出。
而view切換過程當中,不用的資源如果不手動設置爲null會致使變量得不到回收便脫離框架控制而失控了。因此咱們在webapp的過程當中須要注意:
l 釋放沒有使用的閉包
l 觀察者須要獲得清理
l 釋放定時器
l view切換過程當中,在destroy中釋放view相關資源
——感謝艾倫友情支援
在咱們工做過程當中,濫用局部變量極有可能引發閉包陷阱,這個問題不止是性能問題,在邏輯上會引發錯誤,並且不易發現,好比,在AMD閉包中使用一個局部變量
var _attributes = {};
callback ($.extend(_attributes, opts));
如此操做,會改變_ attributes對象,如果一個實例還無問題,可是兩個實例的話便會發生變量污染。
這只是一個例子,可是在代碼中濫用局部變量可能會引發沒必要要的隱憂,戒之慎之。
根據前面的描述,咱們能夠得出一個結論:
不管是view仍是UI組件咱們得提供統一的destroy接口,以便讓用戶繼承釋放資源。
如果view的資源得不到釋放致使heap值太高,webapp模式的網站其價值大減。這裏有幾點能夠考慮:
l webapp中view實例保存不超過5個,多了便釋放dom結構以及內存引用(臨界值本身判斷最優)
l view隱藏時釋放內部資源,解除DOM事件句柄
l UI組件與view相同,須要統一釋放機制
可是單頁應用因爲頁面不會刷新,總有一些資源得不到釋放,此問題任重道遠,平時編寫過程能夠作如下優化:
l 使用函數替換邏輯
讓咱們的函數產生一個返回值替換函數中的大段邏輯,這樣的第一個好處即是邏輯清晰,第二個好處是這些函數在不一樣的函數中,這個函數被使用後便會自動獲得釋放。
l 清理閉包引用
當一個閉包函數或者什麼使用結束後,若不會再使用,便須要手動清理該變量,以便解除閉包之間的引用關係,從而釋放資源。
l 使用對象屬性或者方法
一個對象能夠引用其餘對象的屬性或者方法,好比obj.foo = thatObj;這種狀況下,咱們能夠隨時刪除對象解除引用關係,而後即可以清理資源。
動畫而言建議採用CSS3實現動畫,CSS3中又推薦採用最新的接口,好比使用transform取代top/lelf操做,這樣操做效率搞得多。
如果採用動畫能夠將對應元素設置爲absolute以減小回流,另外最關鍵一點仍是
避免移動DOM樹過多的節點,這個時候須要駁回產品無理需求,好比:
產品要求日期滾屏組件,顯示半年的數據,這半年的數據即是180個DOM樹
這個級別的DOM一旦移動整個手機會直接卡死,甚至構建DOM樹,渲染頁面也會出現假死現象,該問題須要規避。
Application Cache是HTML5爲webapp離線使用而增長的API,與localstorage、cookie等不一樣,Application Cache存儲的是一系列請求資源容許瀏覽器在請求資源時沒必要經過網絡,設計得當的話能夠實現離線應用。
使用Application Cache主要是在網絡性能上提高,有效下降了網絡延遲,提高請求加速
可是也會有一些問題,好比新版本緩存不馬上生效;manifest中的請求路徑相對於manifest文件,而非加載頁面;更新/回滾等問題,因此使用與否還得論證。
移動端常常須要實現區域滾動的需求,成熟的也有IScroll解決方案,可是方案卻不理想。
就官方的例子便會出現如下問題:
l 頭部消失
l 偶爾不能顯示文本框焦點,或者焦點錯位
如果以上問題可忽略,可是文本框不見了這種事情,我是不會接受的
致使的緣由與組織瀏覽器默認事件有關,因此,我這裏不太推薦各位大範圍的使用區域滾動,而改在區域使用,
就去哪兒的ipad版本在一個具備文本框的地方使用了IScroll,其提升的用戶體驗與致使的問題同樣引人入勝。
事實上,小釵及其推崇IScroll庫,雖然說他有這樣那樣問題,可是,IScroll是最有可能帶來移動端革命的庫,由於他能夠:
① 解決webapp區域滾動
② 變相解決fixed問題
③ 解決動畫過程帶來的長短頁問題
總而言之,IScroll方案的提出,是讓webapp媲美native app靠近了一大步,真正的分庭抗禮還須要瀏覽器的支援
click自己在移動端響應是沒有問題的,可是咱們點擊下來300ms 的延遲倒是事實,這種事實形成的緣由就是
手機須要知道你是否是想雙擊放大網頁內容
因此click點擊響應慢,而touch卻不會有這樣的限制,因而移動端的touch至關受歡迎,至於鼠標慢,他究竟有多慢,我會告訴你每次會慢300ms
因此該問題須要處理,具體見:http://www.cnblogs.com/yexiaochai/p/3462657.html#_h2_7
webapp不是一天兩天的事情,總有一天,webapp會綻開其應有的風采!