HTML 5可見性API以及頁面預(yù)渲染
不管是桌面還是Web,減少UI延遲一直是增強(qiáng)用戶體驗的關(guān)鍵。對于原生應(yīng)用來說,減少延遲的最佳辦法就是解耦UI和控制線程,以避免耗時任務(wù)造成UI阻塞,而對于Web,情況有點不同:因為我們的Javascript運行時都是單線程的,我們沒法借助額外的線程來降低延遲,而不得不依賴事件驅(qū)動的編程模型,甚至更糟,即使運算是在本地進(jìn)行的,同服務(wù)器的一次交互也可以很輕易的就消耗掉幾百毫秒。
沒什么好吃驚的,過去幾年我們發(fā)明了無數(shù)的Javascript UI框架,全都是異步的,全部把精力放在如何降低交互延遲。理論上,這些點子都不錯,但是在實際應(yīng)用中,他們都有各自的副作用,比如這些#!,我想大家一定都寫過這種快速消耗客戶端CPU及電池壽命的setTimeout代碼。
實際上,因為瀏覽器的虛擬機(jī)是一個共享資源,我們都不可避免的要遭遇這樣的問題:如果所有應(yīng)用都融洽相處,那么大家都可以得到最佳體驗,但是我們并沒有足夠的動力去這么做。并且問題是,直到最近我們甚至都沒有一個針對這個問題的工具!頁面可見性API是第一個針對這個問題的HTML5提案,再加上瀏覽器的預(yù)渲染功能也試圖幫助我們減少Web應(yīng)用的網(wǎng)絡(luò)延遲——下面就讓我們來一探究竟吧!
瀏覽器預(yù)讀取 vs 預(yù)渲染
渲染一個頁面除了頁面本身的HTML內(nèi)容,往往還需要獲取幾十個額外的資源,如果你看看你的瀏覽器的debug控制臺,就會發(fā)現(xiàn)一個頁面花10幾秒完成渲染是司空見慣的事情,幸運的是,瀏覽器已經(jīng)為我們提供了一些手段來讓讀取更加快速——并行下載,高度優(yōu)化的渲染引擎,以及對于Javascript執(zhí)行速度永無停歇的優(yōu)化,但不管怎么說,這些都還不足以擊敗“原生體驗”。
另外,服務(wù)器也可以幫到我們:像SPDY這樣的新協(xié)議就致力于減少抓取多個資源的網(wǎng)絡(luò)延遲,并且甚至還可以讓服務(wù)端自動推送相關(guān)的頁面資源。但是讓我們想想如果你知道用戶下一步要點擊什么頁面,我們是不是可以做點什么?Firefox 3.5就提供了一個預(yù)讀取API讓我們可以通知瀏覽器預(yù)先抓取后續(xù)請求可能會用到的資源:
- <!-- Specify any & all resources to pre-fetch -->
- <link rel="prefetch" href="/images/big.jpg">
- <!-- or send an HTTP header -->
- Link: </images/big.jpeg>; rel=prefetch
預(yù)讀取是一個很簡單的優(yōu)化,但是它需要你明確的指定每一個單獨的資源,而不是簡單的列出下一個可能的被訪問的URL,所以很難在用戶體驗上帶來大的改善。
而預(yù)渲染就可以很好的解決這個問題:同預(yù)讀取相比,預(yù)渲染不需要指定單個資源,取而代之,瀏覽器會抓取下一個請求的整個頁面并進(jìn)行預(yù)渲染,并且直到你點擊那個鏈接,這個頁面都是不可見的,大約1個月前,Webkit已經(jīng)增加了對預(yù)渲染的支持,并且Google也已經(jīng)發(fā)布了Instant Pages的原型(視頻需翻墻):
預(yù)渲染的利與弊
就目前來看,預(yù)渲染API還存在很大的限制:整個瀏覽器只能預(yù)渲染一個頁面,并且每個tab只能向預(yù)渲染隊列中加入一個頁面,并且,預(yù)加載整個頁面也會增加服務(wù)器和客戶端的負(fù)擔(dān),因此你需要確定你真的需要它,舉個例子,對于Google Web搜索來說,它的搜索結(jié)果頁就可以用到預(yù)渲染,因為他們可以非常確信你有很大的概率會點擊排名第一的搜索結(jié)果。
另外,因為我們現(xiàn)在是預(yù)先渲染整個頁面(HTML,CSS以及JS),這也會對頁面上的交互性內(nèi)容造成影響,如果你的頁面對預(yù)渲染一無所知,預(yù)先加載的頁面可能會白白的浪費我們的CPU,比如向廣告服務(wù)器發(fā)送請求輪換廣告頁面,而用戶實際上根本就看不到這些廣告,為了解決這個問題,Webkit也增加了頁面可見性API:
- function handleVisibilityChange(){
- if(document.webkitHidden){
- pausePageJavascript();
- }else{
- startPageJavascript();
- }}
- document.addEventListener("webkitvisibilitychange", handleVisibilityChange, false);
webkitHidden屬性告訴我們當(dāng)前頁面的狀態(tài),這就解決了可見性的問題,并且webkitvisibilitychange事件還為我們提供了另外一個可能:客戶端可以很簡單的通過這個事件判斷當(dāng)前頁面所在tab是否在后臺運行,這有什么用呢?想象你的程序如果需要定期輪詢服務(wù)器去獲取更新,有了可見性API,當(dāng)你的頁面進(jìn)入后臺運行時,你就可以很容易的暫停或是降低定時器的觸發(fā)頻率,從而節(jié)省客戶端和服務(wù)器的資源。
最小化網(wǎng)絡(luò)延遲
預(yù)讀取以及可見性API都還在開發(fā)中,但我們還是很高興看到有越來越多的客戶端工具來幫助web開發(fā)者降低網(wǎng)絡(luò)延遲帶來的影響,有了這些API,我們就不需要再依賴異步Javascript,如果你有一個多頁面的表單,你就可以在webkit中預(yù)先渲染下一頁的表單,讓客戶端可以得到實時響應(yīng)。
盡管像Chrome這樣的瀏覽器已經(jīng)對后臺運行的Tab做了CPU降權(quán)處理,但有個客戶端API可以判斷程序是在前臺還是后臺運行總是會有好處,讓我們期待Firefox,Opera以及IE也盡快增加這個功能吧!
原文:http://heikezhi.com/2011/07/06/html5-visibility-api-page-pre-rendering/
【編輯推薦】