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

發表於2015-09-30

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

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

為什麼需要資源預載入

大多時候,我們的頁面並不是一次渲染完畢的,而是隨著使用者的操作,不斷修改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屬性可以讓我們獲取到檔案上傳的進度資訊,但對於返回的資料,卻無法直接提供進度資訊,所以要想依靠它來實現還得做其他工作。

相關文章