前端資源預加載並展示進度條

我們經常會看到,一些站點在首次進入的時候會先顯示一個進度條,等資源加載完畢後再呈現頁面,大概像這樣:

然後整個頁面的操作就會非常流暢,因爲之後沒必要再等待加載資源了。尤其是在移動端,或者是頁遊中,這樣做能避免頁面出現白屏(等待加載圖片),很大程度提升用戶體驗。那這種技術是如何實現的呢?其實非常簡單,本文就來從基礎細節探究一番。

爲什麼需要資源預加載

大多時候,我們的頁面並不是一次渲染完畢的,而是隨着用戶的操作,不斷修改DOM節點,如果你動態插入了一個圖片節點,那麼瀏覽器要馬上發一個http請求,把圖片加載下來然後渲染在頁面上,如果用戶此時的網速不佳,那麼加載這張圖片可能就會消耗幾秒鐘時間,此時頁面上什麼都沒有(白屏)。最壞的情況,如果你的應用圖片很多,半天加載不出幾張圖,用戶很可能就在白屏的那幾秒跳走了。在遊戲中更嚴重,主角的圖片如果加載不出來,讓用戶玩空氣去?

除了在DOM中插入圖片節點,其他凡是涉及到要展示一張新圖片的操作,瀏覽器都得即時去請求圖片。比如,爲某個節點添加如下css類來增加背景圖片:

或者是動態修改了src屬性、在canvas繪製圖片等,這些都會即時請求新資源。

那麼,資源預加載爲什麼能解決上述問題呢?

我們預加載的資源,瀏覽器會緩存下來,再次使用的時候,瀏覽器會檢查是不是已經在緩存中,如果在,則直接用緩存的資源,不發送請求,或者由服務端返回304 not modified(304只帶請求頭信息,不傳輸資源)。這樣使用一張圖片的時間會大大縮減,我們的頁面看起來會非常流暢,媽媽再也不用擔心用戶會跳走了~

也就是說,預加載的資源我們並不需要手動保存,由瀏覽器自動放到緩存了。

資源預加載的場景

什麼樣的項目需要預加載資源呢?

範圍應該鎖定單頁面應用,SPA的視圖一般都是一步一步來呈現的,各種資源通過異步請求來獲取,爲了追求原生app般的流暢體驗,可以把一些資源預加載下來。當然對於一些業務相關的圖片資源,也可考慮延遲加載,但延遲加載不是本文討論的範疇。

視圖/圖片較多的專題頁面,或者是需要逐幀圖片來完成的動畫效果,最好都要做預加載。

HTML5遊戲,圖片一般都比較多,而且很多逐幀動畫,必須要預加載,事實上一些遊戲引擎都會提供相應功能。

哪些資源需要預加載呢?

web中包含的資源有很多種,圖片、音視頻之類的媒體文件,另外就是js、css文件,這些都需要發送請求來獲取。那這些資源難道我們都預加載?

當然不是了,預加載也是需要消耗時間的,總不能讓用戶等你加載個幾十秒鐘吧。具體預加載哪些資源,需要基於具體的考慮,也跟你的項目相關。以下是一些我的想法:

js、css文件不需進行預加載。現在寫js基本都用requirejs之類的加載器,而且最後都會進行壓縮合並,將請求數降到最低,最終只有一個文件,有些團隊甚至還將壓縮後的代碼直接放在行內,這樣一個多餘的請求都沒有了。

那麼需要預加載的就是媒體文件了,圖片、音視頻之類。這類資源也得根據實際情況來選擇哪些需要預加載。比如大多數頁面裝飾性圖片就需要預加載,而由業務動態獲取的圖片則無法預加載(預先不知道地址)。用作音效、小動畫的音視頻可以預加載,一個半小時長的視頻就不能預加載了。

預加載的原理與加載進度的獲取

上面都是紙上談兵的一些觀點,下面我們該從技術的角度來思考一下預加載該如何實現。

原理其實也相當簡單,就是維護一個資源列表,挨個去加載列表中的資源,然後在每個資源加載完成的回調函數中更新進度即可。

以圖片爲例,大致的代碼應該是這樣:

這樣就OK啦,圖片已經進緩存,留着以後使用吧。

再說進度,這個進度嚴格來講並不是文件加載的實時進度,因爲我們只能在每個文件加載完成的時候執行回調,無法像timeline中那樣拿到文件加載的實時進度。

計算方法就很簡單了,當前加載完的資源個數/資源總數*100,就是加載進度的百分比了。

資源預加載小插件:resLoader.js介紹

本文的重點終於來了。。。額

根據上面的原理,我寫了一個插件,用來做資源預加載。

具備的特徵如下:

1. 自定義資源列表,用於預加載

2. 自定義onProgress,想展示成進度條還是百分比數字還是個性的設計都可

3. 開始和結束可配置回調函數

4. 只支持圖片的預加載

5. 支持amd、cmd加載器加載,同時支持直接用<script>標籤引入使用

6. 不依賴其他庫

用法如下:

各項參數都直接明瞭,不再多說了。在上面的例子中,我自己定義onProgress函數,做了一個簡單的進度條,你也可以做其他實現。函數爲你傳入了current和total,分別表示當前完成的資源個數和資源總個數,可用於計算進度。

效果可看在線demo:點擊這裏

另外附上下載地址,感興趣的朋友可以拿去使用:http://files.cnblogs.com/files/lvdabao/resLoader.zip

再多說兩句,關於xhr2新特性

前邊的廢話貌似有點多。。。想直接用插件的下載下去用就好,有問題在此留言討論。

這裏想多說的東西是關於加載進度的,我上面說了我們只能獲取到的是進度其實是離散的點,不是連續的。其實利用HTML5的xhr2的新特性我們也可以嘗試獲取更加精確的進度。因爲xhr2新增了一個非常有趣的特性:可以從服務端獲取文件數據。我們以前從服務端返回的數據都是字符串,現在可以直接返回Blob類型的文件。那麼在這裏做一個猜想,能不能利用此特性,做更加精確的進度計算呢?我在此處只是提出一種可能性,還未做實踐。我們知道xhr2新增的upload屬性可以讓我們獲取到文件上傳的進度信息,但對於返回的數據,卻無法直接提供進度信息,所以要想依靠它來實現還得做其他工作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章