Vue3|性能優(yōu)化之緩存

本文介紹幾個(gè)Vue3項(xiàng)目的緩存策略

背景

緩存在性能優(yōu)化中起著重要作用,它可以提高網(wǎng)頁的響應(yīng)速度、給用戶更快速流暢的使用體驗(yàn),同時(shí)還可以減少服務(wù)器負(fù)擔(dān)。接下來從頁面、組件和數(shù)據(jù)三個(gè)層級(jí)說明這次在項(xiàng)目中做的緩存措施。

方案

頁面緩存

頁面緩存適用于內(nèi)容不會(huì)頻繁改變且訪問較多的頁面。通過緩存整個(gè)頁面的HTML內(nèi)容,這樣用戶請(qǐng)求該頁面時(shí),服務(wù)端無需重新生成頁面直接從緩存中獲取即可。由于做了頁面緩存相當(dāng)于組件和數(shù)據(jù)都會(huì)緩存,效率更高一些。然而我們網(wǎng)站所有頁面都會(huì)在右上角展示用戶登錄信息,依賴登錄態(tài)就不適合做頁面緩存了。


組件緩存

接下來考慮做組件緩存。官方給到了一些組件層級(jí)的優(yōu)化點(diǎn),比如:

  • v-once:僅渲染一次,并跳過之后更新,適合本身有一定的渲染成本且無需受父組件的更新影響。API參考
  • v-memo:若條件和上一次相同,則跳過這次更新,適合和v-for配合來優(yōu)化列表,有條件的跳過更新。API參考
  • <keep-alive>:緩存不活動(dòng)的實(shí)例,再次激活時(shí)直接從緩存中恢復(fù)。適合在切換組件中保存組件狀態(tài)。API參考
  • 異步組件:僅在實(shí)際渲染時(shí)再加載內(nèi)部邏輯,適合延遲加載非立即顯示的組件。API參考
  • 虛擬列表:只渲染當(dāng)前可見項(xiàng)且復(fù)用Dom節(jié)點(diǎn),適合大量數(shù)據(jù)列表或表格列表。推薦的三方庫:vue-virtual-scroller、vue-virtual-scroll-grid、vueuc/VVirtualList。

這里主要說下KeepAlive,它是Vue3官方提供的一個(gè)高級(jí)組件,可以在多個(gè)組件動(dòng)態(tài)切換時(shí)緩存被移除的組件實(shí)例,那具體有哪些應(yīng)用場(chǎng)景呢?先來看下屬性:

  • include:緩存指定name的組件
  • exclude:不緩存指定name的組件
  • max:限制可被緩存的最大組件實(shí)例數(shù),避免占用過大內(nèi)存

舉個(gè)例子,有一個(gè)列表頁(左圖)點(diǎn)擊子項(xiàng)后會(huì)在當(dāng)前頁切換到詳情頁(右圖),如果返回會(huì)重新渲染列表頁,此時(shí)可以通過 <keep-alive>緩存列表頁從而實(shí)現(xiàn)返回后位置不變,更符合用戶習(xí)慣。

項(xiàng)目中用的NuxtPage占位,會(huì)根據(jù)當(dāng)前路由動(dòng)態(tài)地加載和顯示相應(yīng)的頁面組件,也就是圖中GameHomeDetails這部分。實(shí)現(xiàn)起來非常簡單(參考方案),只要兩行代碼,首先給想要緩存的列表頁命名如:

defineOptions({ name: "GameHome" });

然后在上一層指定緩存這個(gè)頁面,利用NuxtPage本身keepalive屬性:

<NuxtPage
  :keepalive="{ include: ['GameHome'], max: 2 }"
></NuxtPage>

除了可以保存組件狀態(tài),還可以減少不必要的請(qǐng)求和渲染,讓用戶可以更快看到頁面。

數(shù)據(jù)緩存

上面的組件緩存只是客戶端層面的,只能提高單個(gè)用戶在本次瀏覽過程中的體驗(yàn),還可以利用SSR將請(qǐng)求數(shù)據(jù)緩存在服務(wù)端,以提高其他用戶瀏覽同個(gè)高頻頁面的加載速度。思路如下:

private static cache = new LRUCache({
  max: 100, // 保存100個(gè)數(shù)據(jù)
  ttl: 1000 * 60 * 60 * 24, // 保存1天
});
  • 設(shè)置緩存類型,控制緩存范圍,比如個(gè)性化數(shù)據(jù)只緩存在本地
export const enum CacheType {
  NONE = 0, // 不緩存
  ONLY_CLIENT = 1, // 僅緩存在客戶端
  ONLY_SERVER = 2, // 僅緩存在服務(wù)端
  BOTH_CLIENT_SERVER = 3, // 客戶端和服務(wù)端都緩存
}
  • 在請(qǐng)求接口增加一個(gè)緩存類型參數(shù),滿足條件時(shí)get/set對(duì)應(yīng)緩存
public async request(
  name: string,
  path: string,
  params?: object,
  extraOption?: object,
  cacheType: CacheType = CacheType.NONE,
) {
  return useAsyncData(
    name,
    () => {
      // 1、先獲取緩存數(shù)據(jù),生成唯一緩存key = 請(qǐng)求路徑 + 公參 + 私參
      const cacheKey = CacheMgr.generateKey(cacheType, path + this.locale, params);
      if (CacheMgr.isCacheScene(cacheType)) {
        const cache = CacheMgr.get(cacheKey);
        if (cache != null) {
          return cache;
        }
      }
      // 2、無可用緩存發(fā)起請(qǐng)求
      const response = await $fetch(...);
      // 3、統(tǒng)一處理異常情況
      this.handleError(response.error);
      // 4、添加緩存
      if (CacheMgr.isCacheScene(cacheType)) {
        CacheMgr.set(response, response.error, cacheKey);
      }
      return response;
    },
    extraOption ?? {},
  );
}
  • 還要注意版本升級(jí)時(shí)清理歷史緩存,避免不可用

總結(jié)

通過以上緩存措施,可以看到,當(dāng)緩存在客戶端時(shí),可以提高用戶多次訪問同一頁面/模塊的速度;當(dāng)緩存在服務(wù)端時(shí),還能提高其他用戶訪問同一頁面/模塊的速度,同時(shí)給服務(wù)器減壓。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容