首頁 > 軟體

vue元件程式碼分塊和懶載入講解

2022-04-11 13:01:02

前端開發中,隨著業務和頁面增加,以元件為基本單位的結構下,元件數量會增長極快,為了優化我們會很顯然地想要進行一些工作:

  • 程式碼分塊
  • 懶載入非必要資原始檔

非必要資源,指的首次渲染出某頁面所不必要的資源,如因為使用者操作才出現的圖片、彈窗等。

程式碼分塊和懶載入在頁面層面具有極大的優化作用,使用者很可能只是瀏覽dashboard頁面,可能根本就不會去看詳情等頁面,那我們就不必將詳情頁面的程式碼和dashboard頁面程式碼混在一起,使用者看某個頁面時只載入那個頁面對應的資源即可,可以較大地提升使用者體驗。本文就在Vue工程下如何在元件層面設定程式碼分塊和懶載入進行講解。

本文在@vue/cli 3以上版本。

懶載入元件

一般來說,Vue中使用某元件過程大致如下:

<script>
// Home.vue
import HelloWorld from '@/components/HelloWorld.vue'
export default {
  components: {
    HelloWorld,
  },
}
</script>

這是我們最熟悉的方式了,我們在存取Home.vue時,Webpack為我們保證了HelloWorld.vue一定是存在的,這是由依賴關係決定的(Home.vue依賴於HelloWorld.vue)。

這很正常對吧,但是如果HelloWorld.vue是非必要資源呢,比如需要使用者點選一個按鈕才會出現的彈窗或者是預設隱藏的內容,只當某些條件觸發時才出現的頁面區域呢?如果是上述情況,當我們存取Home.vue時顯然沒必要馬上就將HelloWorld.vue請求過來,而且設定方法也及其簡單:

<template>
  <div class="home">
    <button @click="() => showHello = true">Hello</button>
    <HelloWorld v-if="showHello" />
  </div>
</template>
<script>
// Home.vue
export default {
  components: {
    HelloWorld: () => import('@/components/HelloWorld.vue'),  // A
  },
  data() {
    return {
      showHello: false,
    }
  },
}
</script>

只需像A行一樣簡單處理一下即可一舉兩得:HelloWorld.vue會被打包成獨立為單獨的js檔案,而且只有當我們點選按鈕時,這個獨立的js檔案才會被請求,這樣能夠減小主程式碼塊的體積。

簡單分析一下:import()會返回一個元件Promise,現在基本上所有的打包工具都理解此語法,而且還會觸發Webpack的程式碼分塊(Webpack 2之後)。

注意:Vue不會在意某個元件,直到它要被渲染出來。以上例來說,只有當我們觸發了按鈕,HelloWorld.vue才有了意義。

即使所有元件都可以設定懶載入,但是別濫用,大部分情況下只對非必要資源設定懶載入即可,像上例如果HelloWorld.vue是Home.vue中是一直存在的,那樣設定懶載入可能會適得其反,載入了Home.vue對應的js檔案後會馬上請求HelloWorld.vue對應的js檔案,如果HelloWorld.vue對應的js檔案比較小,那得到的收益可能不足以抵消一次http請求帶來的消耗。

問題與解決方案

元件懶載入雖然好處極多,但仍有缺陷,如上例點選按鈕後需等待HelloWorld.vue對應的js檔案被請求執行後頁面才會做出相應變化,這就涉及到載入狀態和錯誤狀態的處理(雖然一般情況下不會有問題,因為都是些小檔案,載入極快,但也有例外),所幸Vue也為我們考慮到了這些:

載入中元件

<script>
// Home.vue
import LoadingComponent from '@/components/Loading'
export default {
  components: {
    HelloWorld: () => ({
      component: import('@/components/HelloWorld.vue'),
      loading: LoadingComponent,  // 載入HelloWorld.vue對應js檔案中展示
      delay: 300,                 // loading的延遲生效時間
    }),
  },
  data() {
    return {
      showHello: false,
    }
  },
}
</script>

從使用者體驗方面來說,般來說500ms內的響應時間還不至於失去使用者的注意力,所以可以為loading設定一個延遲時間,預設200ms內載入完成不會出現loading,當然也可以像上面一樣手動設定一下delay,單位ms。

錯誤處理元件

<script>
// Home.vue
import ErrorComponent from '@/components/Error'
export default {
  components: {
    HelloWorld: () => ({
      component: import('@/components/HelloWorld.vue'),
      error: ErrorComponent,  // 載入HelloWorld.vue對應js檔案失敗時展示,如檔案不存在
      timeout: 2000,          // 檔案載入的超時時間,超出時間未載入完成,會觸發ErrorComponent
    }),
  },
  data() {
    return {
      showHello: false,
    }
  },
}
</script>

出現錯誤的情形主要有以下幾點:

  • 網路連線不通 / 伺服器錯誤
  • 檔案不存在(特別注意重新部署後之前版本的檔案被刪除,而使用者還未重新整理頁面)
  • 載入超時(預設是沒有超時時間的,不過可以像上面一樣通過timeout屬性設定,單位ms)

preload 和 prefetch

Vue還為資原始檔設定了預載入策略,即使用<link rel="prefetch">和<link rel="preload">策略,在build後的index.html檔案中或者開發模式下瀏覽器的Network面板裡可以具體檢視。關於兩者的具體用法這裡就不贅述了,這裡說一下兩者差異之處:preload的優先順序比prefetch的高,一般來說當前頁面的必要資源可以使用preload策略,當前頁面的非必要資源和其他頁面的資源使用prefetch策略。

通過設定資源預載入,瀏覽器為我們預先預先載入資源,在使用者用到某些資源時可以及時響應,可以在提升首次載入效能的同時為使用者後續的操作提供良好的體驗。

prefetch在Safari中暫時還不支援,所以懶載入在Safari中表現地相對較差。

總結

Vue中使用懶載入和程式碼分塊對產品進行優化,簡單實用,但是這其中存在著權衡,如果專案較小,打包檔案並不大,則可能不需要進行程式碼分塊和懶載入,畢竟http請求也是挺貴的。

當專案較大時,使用懶載入和程式碼分塊就可以顯著地提升效能,但是同樣注意那需要由後來的請求彌補的,但所幸目前大部分瀏覽器都支援資源預載入策略,搭配使用效果更佳。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com