每次跟朋友談起HTML5,就會有人說可以先用HTML5的方式就是把DOCTYPE先改了,因為目前很多頁面都還是用傳統(tǒng)的方式,HTML5的方式,本身是兼容IE瀏覽器的,從IE6到IE10都可以,包括高級瀏覽器都支持,所以說擁抱HTML5最簡單的方式就是把DOCTYPE給改了。
從性能角度來說,HTML5首先是縮減了HTML文檔,使這件事情變得更簡單,首先,從用戶可讀性上說,原先一大堆東西,像初學(xué)者第一次看到這些東西是看不懂的,而HTML5的聲明方式對用戶來說顯然更友好一些;最后,文檔編碼的聲明,用HTML5方式的話,就很簡單。
1、更簡潔的標(biāo)簽
接下來可能并不是一件很常見的事情,但是卻是我比較推崇的,使用更簡潔的標(biāo)簽方式。
HTML5從這個名字大家可以聽出,它是從HTML4繼承過來的,HTML4里面有嚴(yán)格模式跟過渡模式,HTML5是支持這種過渡模式的,就是你可以不把一些標(biāo)簽閉合,但是,我并不推薦所有的標(biāo)簽,比方說BODY標(biāo)簽的不閉合,這種我們不推薦。
但是像P標(biāo)簽最常用的,還有列表標(biāo)簽LI,為什么這樣說?首先從視覺的角度來說,這樣的方式更簡潔一點,然后關(guān)鍵的是在文檔傳輸過程中,內(nèi)容會更少。
HTML5標(biāo)簽屬性的聲明支持三種方式:單括號、雙括號和不加括號,為了減少文檔大小,我是選擇不加雙引號的方式或單引號的方式,但是要注意,假設(shè)是類屬性的聲明,因?qū)傩钥赡馨ǘ鄠€類,多個類的時候則必須用括號括起來,在這方面,給大家看一下谷歌的一個實踐,谷歌自己有一個頁面完全實踐了上面的東西,文檔的大小減少了20%,使HTML文檔的傳輸減少了20%,如果把整個都實踐起來,可以達(dá)到5%—20%之間的減少,這是第一步,縮減HTML文檔的大小。
2、預(yù)取
接下來講Prefetching,預(yù)取,是優(yōu)化的另一個思路,我們現(xiàn)在優(yōu)化的思路無非就是少,很多都是從少的角度,比方說前面把文檔大小減少,把圖片的大小減少,很多張的圖片變成一張精靈圖,都是為了把發(fā)送請求的數(shù)量減少,預(yù)取的話,是另一種思路,提早加載好資源,用戶去點的時候,實際上已經(jīng)加載好,那肯定是更快了。
預(yù)取,一共有兩部分:一部分是資源的預(yù)取;還有一部分是DNS的預(yù)解析。
資源預(yù)加載有幾個點需要注意:
(1)、預(yù)加載只是在瀏覽器空閑的時候才會去拉,但不保證一定會去拉,這是很重要的一點,因為本身瀏覽器有一個全局的監(jiān)聽器,這是內(nèi)部的一個接口,當(dāng)瀏覽氣空閑的時候,它會去執(zhí)行瀏覽器空閑的時候應(yīng)該做事情,但是這個空閑的回調(diào)不一定被觸發(fā),所以說并不保證一定會執(zhí)行預(yù)加載。
(2)、Chrome不支持HTTPS資源的預(yù)加載,像Alipay是HTTPS的頁面,Chrome不會去預(yù)拉取。
(3)、一個預(yù)拉取的頁面雖存在后不可見,實際上它是在正常解析,假如說我預(yù)拉取登陸頁面,登陸頁面有很多資源,比方說有圖片,有CSS文件,JS文件,它是從上往下正常的會被解析,解析的過程中,這個頁面沒有顯現(xiàn),但是它實際上是存在的,在HTML5里面,可通過document.visibilityState得到當(dāng)前頁面狀態(tài),通常頁面有兩種狀態(tài),可見與不可見,但是現(xiàn)在有一個新的狀態(tài),叫做預(yù)渲染的狀態(tài),可以直接通過document.visibilityState是否等于prerender來判斷頁面是否在預(yù)渲染狀態(tài)。
3、圖片優(yōu)化
接下來是關(guān)于圖片的優(yōu)化,圖片永遠(yuǎn)是又愛又恨的元素,因為當(dāng)圖片多的時候,會嚴(yán)重拖垮整個頁面的加載速度,關(guān)于圖片的優(yōu)化方式,之前的文中已有很多介紹,總結(jié)起來主要有三點:使用精靈圖、優(yōu)化圖片的大小,使用DATA URI,具體這里就不細(xì)說了。
圖片優(yōu)化的另一個思路是:no-image,拋棄圖片,擁抱CSS3,原先需要設(shè)置一張圓角效果的圖片,現(xiàn)在使用CSS3中的border-radius;原先需要設(shè)置陰影效果的圖片,現(xiàn)在使用CSS3中的box-shadow;原先需要設(shè)置漸變的背景圖片,現(xiàn)在使用CSS3中的gradient。
4、DNS解析
接下來是關(guān)于DNS的解析,有時候我們登入頁面,對用戶可能點的地方相對而言是比較難探測到,當(dāng)然有時候我們會做一些埋點來探知用戶下一步行為大部分是往里走,但有些情況下,我們不知道用戶下一步具體會走到哪一個頁面的時候,但是我們知道他要走到哪一個域?這個時候,我就可以預(yù)解析DNS,因為實際上,整個頁面的請求過程中間有一個很長的DNS的解析過程,如果說這個我們提前做了,就可以更進一步讓用戶看到這一頁面。
比如Q+壁紙的案例,Q+壁紙是Q+某一個系統(tǒng)系統(tǒng),首先Q+整個的架構(gòu)是基于WEB+客戶端,我們現(xiàn)在看到的就是一個WEB的頁面,雖然它外面是一個客戶端的殼,但是它的心是WEB的,整個過程在我們第一次在完成的時候,因為圖片比較多,所有的靜態(tài)資源是分配到十幾個靜態(tài)服務(wù)器上,也就是說,如果我要去拉的時候,我就要解析10個DNS,這個時間是相當(dāng)耗時的,最慢的時候可能會延遲幾秒鐘,這是我們?nèi)庋勰芨杏X到的。
如果進行DNS預(yù)解析,因為本身資源我不知道具體是哪一個,所有圖片都是隨機的,所以我們只能說在DNS預(yù)解析上下功夫,來提升它的速度,這樣的話,從原來可能需要2秒鐘,我就變成1秒鐘。
接下來講Q+中的應(yīng)用,我們會像QQ里面一樣,QQ里面跟Q+都有很多文字鏈,就是窗口的左下角有一個文字APP信息的推送,這邊是通過WEB時時去拉取后端,后端拉取過來然后在前臺顯示,但是在某一個時期,其實所有的APP它一共推送的運營信息是固定的,如果說按某個具體APP去分析每個文字鏈對應(yīng)數(shù)組的話,這個時候是非常大數(shù)據(jù),因為這里一個就大概有達(dá)到三四百個字節(jié),從優(yōu)化的角度說,我們把這些每次拉區(qū)過來的存在本地,再存上本地的localStorage,我們是同一域,所有的APP之間的信息都是可以相互訪問的,然后就是把所有拉過的ID,就不會再重新拉一遍。
在這里也有一個需要注意的點,localStorage目前很多廠商的實現(xiàn)是同步的,如果你大量地調(diào)用localStorage這個接口,實際上他會阻塞你的渲染進程,這個時候,當(dāng)用戶往下拖動頁面的時候,然后你這個時候又正好在做存儲數(shù)據(jù),這個數(shù)據(jù)又比較大,這個時候用戶就會感覺你這個頁面非常卡,之前他們都有討論這個問題,本身這個接口的設(shè)計IE是設(shè)計成異步的,他們設(shè)計是成同步,這個會導(dǎo)致在調(diào)這個借口的時候,假設(shè)你程序比較多,因為有一個序列化的過程,序列到磁盤,這樣的話,整個過程就會顯得比較慢,再加上本身localStorage可以做不同的窗口之間共享這個數(shù)據(jù),它會在這個數(shù)據(jù)上加鎖。
如果大量地數(shù)據(jù)在調(diào)用這個本地接口,它就會顯得比較卡,所以目前沒有什么特別好的解決方案,但是這是需要記住的,即使說目前最大的五點多兆,如果你用了五點多兆,會讓用戶很悲催,因為你如果一去調(diào)用這個借口,用戶在拖用鼠標(biāo),就覺得非常卡。
5、離線存儲
接下來講離線存儲在性能方面給用戶帶來的好處,首先是進離線存儲的定義文件,在Q+中所有的系統(tǒng)模塊,都是有定義離線支持,就是說所有的應(yīng)用,如果網(wǎng)斷了,還是可以用,在文檔中加入MANIFEST的文件,MANIFEST是一個定義文件,聲明當(dāng)前頁面哪些是需要存儲在本地的?哪些是不需要存儲的?哪些如果說請求失敗,應(yīng)該用哪些新的圖片或者什么來代替?這樣分三塊:
(1)、CACHE,哪些需要存儲到本地。
(2)、NETWORK,是不會存儲在本地的,它每次都回去請求一遍但是這里需要指出的是,本地存儲跟瀏覽器存儲實際上是兩回事情,他們存的是兩塊不同的地方,即使NETWORK這邊需要告訴APP說,我需要每次都拉一次,因為像Chrome,他這個存儲緩存是非??蓯旱模容^難清除的,必須通過手動去清除,才能完全生效,所以說你即使設(shè)置了不要讓它存儲在本地,但是瀏覽器可能本身把它存儲起來了,因為他存的是兩塊不同地方。
(3)、FALLBACK,如果說一個圖片假如說請求失敗,它是404,那要用什么圖片代替?我覺得這個比較好玩。
對于MAEIFEST的設(shè)置,保定SEO覺得MANIFEST這里需要注意的是三點:
①、MANIFEST同源限制。
②、MIME類型必須為text/cache-manifest,這是標(biāo)準(zhǔn)的,如果是其他格式,都不會生效。
③、CHROME,如果要看這個東西有沒有生效,可能通過CHROME這個偽協(xié)議的方式在瀏覽器輸入:chrome://appcache-internals
關(guān)于如何去更新應(yīng)用的緩存,為什么要離線存儲?離線存儲在本地,當(dāng)瀏覽器知道你有離線存儲你,它會首先去離線存儲的目錄下,去找這個資源是否已經(jīng)被Cache,當(dāng)它已被Cache的時候,他就直接從這邊拿到這個資源,不會再去發(fā)送一個請求,因為瀏覽器的請求是這樣的,當(dāng)有離線存儲的話,就連請求都不會發(fā),所以說會更快,如果說有的時候我們需要更新,更新的時候怎么辦?
用戶可以手動去清除瀏覽器的Cache,這個時候自動把本地存儲給清除了。
修改MANIFEST的任何內(nèi)容,這是比較推薦的方式,也是我們線上用的方式,就是說我們可以修改里面的的具體項目,但是這里應(yīng)該最好是修改注釋,因為我每次發(fā)布的時候,我們自動發(fā)布機制,發(fā)布的時候在上面注釋修改一下就可以了,這樣的話,每次發(fā)布的內(nèi)容,都會實時同步到客戶端的本地。
通過程序去執(zhí)行,程序的就是window.applicationCache.update(),就是我要去操作離線存儲,其實我有時候叫應(yīng)用存儲,因為它的語意就是應(yīng)用存儲,我們?nèi)ナ謩拥母聭?yīng)用存儲。
6、Web Worker
接下來Web Worker,Web Worker是一個多線程的JS進程,應(yīng)用場景其實我們在線上的話,是沒有的,我就不講了,但是可以講下具體我看到過的應(yīng)用場景。
首先介紹一下Web Worker是什么東西?它是一個OS級別的線程,之前我們模仿多線程,實際上都是多開一個窗口,但是現(xiàn)在的話,瀏覽器本身就提供了,這個會讓操作帶來更多便利,是讓我們整個文檔比較重,并不是很建議的方式。
然后WebWorker訪問能力是有限的,它并不能訪問到很多全局對象,比如說documnet對象它是訪問不了的,WebWorker最適合的場景就是CPU密集型的計算操作,之前我們做游戲的時候,我們用BOX2D,應(yīng)該很多人聽到過,它涉及到大量的計算,就是整個頁面里面,下面所有的物體要去計算它們的碰撞關(guān)系,這個計算量是非常大的。
但是如果放在當(dāng)前的JS的進程里面去執(zhí)行,這個計算量一大,一計算,整個頁面就非???,但是如果用WebWorker去做,它是異步的過程,實時的發(fā)送過去,在計算的過程中還能干其他事,這就是多線程。
7、設(shè)備API
講一下設(shè)備API,設(shè)備API我覺得最重要在性能方面,也是目前實現(xiàn)最早的API,一個是CONNECTION,就是網(wǎng)絡(luò)帶寬,這個有什么作用?
在中國這個場景下,必須得記住,很多用戶的網(wǎng)速依舊是很低的,我們希望讓用戶網(wǎng)速低的時候,能夠自動降級到一個比較低的方案,如果用現(xiàn)有的技術(shù),我們是做不到的,但是使用設(shè)備API我們是可以的,因為我們知道,從設(shè)備上可以取到這些信息,它的寬帶是多少,多少寬帶的時候我們能干的事情,比方說寬帶好的時候,我就用高清圖片,寬帶比較低的時候,就用清晰度比較低的圖片。
8、CANVAS
接下來是CANVAS,講CANVAS的幾個性能優(yōu)化點,用了這些東西,性能會有10倍的提升。
(1)、每個CANVAS就是一個畫布,我們要去渲染一個圖形的時候,我們是可以把它分層的,就是像PS里面一樣,是一層兩層三層,很多用戶在做游戲的時候,直接把所有東西仿放到一個層里,一更新所有的東西都要更新,但如果你把它分層,你讓背景放在背景層,角色放到角色層,這樣的話,我要更新角色的時候,只會更新角色,背景層不需要變,讓CPU干的事情更少了,性能自然而然就提升了。
(2)、context.drawImage,不要去縮放圖片,我們一開始就犯了一個錯誤,我們的美工做的圖片始終跟我們不一致,然后我們要去縮放圖片,因為本身設(shè)備它的圖片大小是這樣的,我們必須按比率縮放圖片,縮放圖片以后發(fā)現(xiàn)在低端設(shè)備下,比方說iPad或者iPhone就會非常卡,我們就想為什么?就進行代碼上的分析,當(dāng)用這個方法時候,花費的時候特別多。
(3)、requestAnimationFrame,這是專門為渲染優(yōu)化的一個方法,它本身的原理是這樣的,當(dāng)瀏覽器每過一楨的時候,會觸發(fā)這個方法,當(dāng)我在觸發(fā)的時候,Canvas得到這個瀏覽器已經(jīng)準(zhǔn)備好做下楨的事情,如果用傳統(tǒng)的方法,是不會去考慮你更多的東西,它只會知道我過了多少時間,我就要執(zhí)行。
假如說用戶之前被阻塞了,每10秒鐘執(zhí)行這一方法,在10秒之內(nèi),實際他之前的事情還沒有做完,然后這個事情就會被延后,它就是為了動畫看上去更流暢而優(yōu)化的,因為每一楨的時候,它就告訴你說,你可以做一些事情。
HTML5應(yīng)用程序可以說是剛剛上路,現(xiàn)在你可以看見非常簡單且基礎(chǔ)的完全圍繞HTML5創(chuàng)建的移動“框架”以及配套技術(shù),我認(rèn)為對開發(fā)者來說,重要的是在核心中處理解決這些問題,且不要用封裝掩蓋它。