一次Web端大量圖片同時載入卡頓問題的優化之旅

蘇格團隊發表於2019-04-22
  • 蘇格團隊
  • 作者:Jason

背景

由於業務的需要,筆者最近需要實現一個大量圖片同時載入的需求。在實現這個需求的過程中,筆者遇到了很多的坑,也總結了一些優化方案。這裡將筆者使用或準備使用的優化方案總結一下。

具體場景

在描述如何解決問題,我們現在先來申明,問題是什麼? 筆者的需求大概是在某個頁面顯示 1~1000張200~500k大小的圖。好訊息是這些圖片來源於本地硬碟而非網路。(否則這個問題就要變成優化網路....)

踩坑歷程

由於不是純前端的專案,筆者可以從本地資料夾中讀取檔案。然後一段程式碼劈里啪啦的就出現了。

    const fileList = this.props.fileList;
    return (
        <div className="list-wrapper">
            {
                fileList.map((file) => {
                    <img className="img-item" src={file.src}>
                })
            }
        <div>
    )
複製程式碼

就在筆者滿心歡喜的認為這個需求基本搞定了,該去樓下加雞腿的時候。無情的現實狠狠的抽了我一巴掌。隨著網頁的重新整理,一張純白的畫面展示在了我的面前,然後只見圖片一點一點的從上面載入出來。 我不禁陷入了沉思,是CPU跑不動道了還是記憶體飄了?在一想,我這電腦都這個表現,真要上線了,這客戶能忍受嗎?不對,就這表現,沒上線前產品小姐姐就的把我ko了...

方案一 懶載入

這種場景下想必大家第一反應也是懶載入。 簡單介紹一下圖片懶載入。常見的圖片懶載入方案是指頁面載入時只渲染螢幕可見區域及周圍的圖片。當頁面滾動時再載入需要顯示的圖片。
出於提高效(tou)率(lan)的目的,筆者在網上找了個比較好用的懶載入庫然後引入專案。 然而,情況並不樂觀。因為該需求場景下每一張圖片的寬高都是 50*50,那麼在PC端常見的 1080p 的裝置上首屏需要顯示的圖片達到了400+張
即便我們忽視這個問題,當使用者滾動網頁速度很快時圖片載入的體驗也是不ok的。所以懶載入並不是萬能的。

方案二 預載入

首先我們要知道,在硬體效能不變且CPU排程不能更積極的前提下。理論上我們無法減少圖片渲染的時間。所以我們只能想辦法調整圖片渲染的方式來提高使用者的體驗。 所以我們採用預載入的方式。

    const fileList = this.props.fileList;
    fileList.forEach((element) => {
        let img = new Image();
        img.src = element.src;
        img.onload = () => {
            // 渲染這張圖
            ...
        }
    })
複製程式碼

當然我們也可以使用img.decode()方法對圖片進行解碼,它會返回一個promise物件。

img.decode().then(() => {
    // 渲染這張圖
     ...
})
複製程式碼

採用了這套方案後,圖片會一張又一張的載入。然而,載入的速度實在是不敢恭維。如果使用者想看最後那張圖片,那他只能在哪裡進行長久的等待...

方案三 懶載入 + 預載入

眾所周知,3 = 1 + 2。 所以方案三就是方案一和方案二的結合體。 首先我們載入一張圖片未載入時的底圖(佔位)。而後我們繼續採用方案二的方式進行圖片逐個的預載入。 當使用者滾動圖片時,我們便改變下一站預渲染的圖片為使用者可見區域的第一張。 然而,情況還是不樂觀。當使用者的滾動條勻速直線不停的往下運動時,效果依然很差。

終結方案

綜合上面幾種方案,基本能優化的我們都已經優化了。那如繼續何提高使用者的體驗呢?似乎,我們只能從圖片本身去下手?
上文也提到,在我所面臨的需求場景下一張圖片的顯示寬高為50 * 50。 而圖片的大小為200~500k。所以我們可以採用縮率圖的方式,先渲染一張3~5k大小的縮圖,等使用者點選圖片檢視詳情時再去渲染大圖。 採用縮圖的情況下我們再使用方案三進行優化,效能表現幾乎就可以滿足這個場景下使用者的需求了。

其他

當然,上面的幾種優化方案只是我在某個專案中使用。我們仍然可以採用例如圖片漸進式增強,CDN快取,圖片壓縮,設立單獨的資源伺服器等諸多方式。圖片的載入優化本身也是一個前端老生常談的問題,業內已經有太多太多的解決方案。如果你有更好的方案,你也可以在下面留言告訴我。謝謝觀看。

相關文章