nuxt api緩存,組件緩存,頁面緩存


前言

SSR指服務端渲染,即頁面是通過服務端渲染生成后返回給客戶端的,SSR主要為了提高頁面加載速度,改善用戶體驗,也可用於SEO搜索引擎優化。

Nuxt.js 官方定義: Nuxt.js 是一個基於 Vue 的通用應用框架。 通過對客戶端/服務端基礎架構的抽象組織,Nuxt.js 主要關注的是應用的 UI渲染。我們的目標是創建一個靈活的應用框架,你可以基於它初始化新項目的基礎結構代碼,或者在已有 Node.js 項目中使用 Nuxt.js。

個人理解:Nuxt.js 就是預設了開發服務端渲染應用所需要的各種配置, 使用 Webpack 和 Node.js 進行封裝的基於Vue的SSR框架。

背景

我們部門從事的都是面對用戶的業務需求開發,面對用戶,意味着對頁面的體驗要求會更高,最直觀體驗是頁面首屏的加載速度,加載速度優化是我們體驗優化的長期、重要的一部分;本文的起源正是首屏加載速度優化。

頁面加載速度優化的核心包括三點:減少資源文件的請求數量;減小每個資源文件的大小;提高每個資源的加載速度;

諸如合並API訪問,壓縮混淆文件,支持webp圖片,資源cdn緩存等等常用辦法,都是以上面三個核心為出發點的; 這些常用辦法基本都可以通過webpack配置,公司基礎服務,代碼較小的變更完成。

我們負責的各主流量入口頁面,已基本做過以上常用的優化,但由於主入口頁面資源量較大的原因,優化后並不能達到預期的效果,我們需要探索其它優化方案。 我們快速想到了用SSR的方案進一步解決加載速度問題,從零開始的搭建服務端渲染應用相當復雜,肯定會涉及到服務端的開發,作為獨立的前端團隊,成本較高昂; 我們決定嘗試是否能找到一種成本較低的現有SSR框架,以達到目的;

因主入口頁面技術棧為vue,方案調研中自然而然的看到了Nuxt.js此種基於Vue的SSR框架; Nuxt.js和項目技術棧匹配度急高,學習成本極低,自然成為我們的第一選擇;

我們引入Nuxt.js,最初只是利用了服務端異步獲取API接口數據和服務端渲染兩項功能,去重構了我們的項目,重構后效果基本達到我們的預期,正常網絡狀態下,基本可以達到秒開; 入口頁面,團隊是作為一個長期的項目進行不定期優化的,我們逐步圍繞Nuxt.js框架,對項目做了進一步優化升級,本文主要介紹我們Nuxt.js頁面優化的進一步探索與實踐

探索與實踐

我們主要的探索與實踐可行方向主要有兩個:

一、Nuxt.js特性合理應用

應用到的特性主要包括asyncData異步獲取數據、mounted不支持服務端渲染、no-ssr組件不在服務端渲染中呈現;

通過相關特性做到API數據和頁面結構合理拆分,首屏所需數據和結構通過服務端獲取並渲染,非首屏數據和結構通過客戶端獲取並渲染。

示例代碼:

no-ssr結構拆分

<template>
 <div>
 <!-- 頂部banner -->
 <banner :banner="banner" />
 <!-- 非首屏所需結構,通過no-ssr組件達到不在服務端渲染目的-->
 <no-ssr>
 <!-- 商品列表 -->
 <prod-list :listData="listData"/>
 </no-ssr>
 </div>
</template

API數據拆分

export default {
 async asyncData({ app, query }) {
 try {
 // 獲取頁面頂部輪播圖信息
 const getBanner = () => {
 return app.$axios.$get('zz/zy/banner')
 }
 // 獲取底部配置信息
 const getFooter = () => {
 return app.$axios.$get('zz/zy/footer', {
 params: {
            smark: query.smark
 }
 })
 }
 // 並發獲取首屏數據,服務端獲取
 const [banner, footer] = await Promise.all([getBanner(), getFooter()])
 return {banner: banner, footer: footer}
 } catch (e) {
      console.log('interface timeout or format error => ', e)
 return {}
 }
 },
  mounted() {
 // 非首屏使用的數據, 客戶端獲取
 this.loadListData()
 },
  methods: {
    loadListData() {
 this.$axios.$get('zz/zy/list').then(() => {
 // 數據處理邏輯
 })
 }
 }
}

二、服務端引入緩存

服務端開發意味着緩存可作為性能優化的最直接法門,Nuxt.js作為一種服務端渲染框架,也不例外;針對不同的頁面,不同的數據狀態,可主要區分為下面三類緩存:

1、API接口數據緩存

將服務端獲取的數據,全部緩存到node進程內存中,定時刷新,有效期內請求都通過緩存獲取API接口數據,減小數據獲取時間;

此種緩存適用於緩存的部分API數據,基本保持不變,變更不頻繁,與用戶個人數據無關。

示例代碼

import LRU from 'lru-cache'
 const CACHED = new LRU({
    max: 100, // 緩存隊列長度
    maxAge: 1000 * 60 // 緩存時間
 })
 export default {
 async asyncData({ app, query }) {
 try {
 let banner, footer
 if (CACHED.has('baseData')) {
 // 存在緩存,使用緩存數據
 let data = CACHED.get('baseData')
          data = JSON.parse(data)
          banner = data.banner
          footer = data.footer
 } else {
 // 獲取頁面頂部輪播圖信息
 const getBanner = () => {
 return app.$axios.$get('zz/zy/banner')
 }
 // 獲取底部配置信息
 const getFooter = () => {
 return app.$axios.$get('zz/zy/footer', {
 params: {
                smark: query.smark
 }
 })
 }
 [banner, footer] = await Promise.all([getBanner(), getFooter()])
 // 將數據寫入緩存
          CACHED.set('baseData', JSON.stringify({ banner: banner, footer: footer}))
 }
 return {mods: mods, footer: footer}
 } catch (e) {
        console.log('interface timeout or format error => ', e)
 return {}
 }
 }
 }

2、組件級別緩存

將渲染后的組件DOM結構存入緩存,定時刷新,有效期通過緩存獲取組件DOM結構,減小生成DOM結構所需時間;

適用於渲染后結構不變或只有幾種變換、並不影響上下文的組件。

示例代碼:

nuxt.config.js配置項修改

const LRU = require('lru-cache')
module.exports = {
  render: {
    bundleRenderer: {
      cache: LRU({
        max: 1000, // 緩存隊列長度
        maxAge: 1000 * 60 // 緩存1分鍾
 })
 }
 }
}

需要做緩存的 vue 組件, 需增加 name 以及 serverCacheKey 字段,以確定緩存的唯一鍵值。

export default {
  name: 'zzZyHome',
  props: ['type'],
  serverCacheKey: props => props.type
}

如果組件依賴於很多的全局狀態,或者狀態取值非常多,緩存會因頻繁被設置而導致溢出,這樣的組件做緩存就沒有多大意義了;

另外組件緩存,只是緩存了dom結構,如created等鈎子中的代碼邏輯並不會被緩存,如果其中邏輯會影響上下邊變更,是不會再執行的,此種組件也不適合緩存。

3、頁面整體緩存

當整個頁面與用戶數據無關,依賴的數據基本不變的情況下,可以對整個頁面做緩存,減小頁面獲取時間;

頁面整體緩存前提是在使用Nuxt.js腳手架工具create-nuxt-app初始化項目時,必須選擇集成服務器框架,如express、koa,只有這樣才具有服務端中間件擴展的功能。

示例代碼:

服務端中間件middleware/page-cache.js

const LRU = require('lru-cache')
let cachePage = new LRU({
 max: 100, // 緩存隊列長度
 maxAge: 1000 * 60 // 緩存1分鍾
})
export default function(req, res, next){
 let url = req._parsedOriginalUrl
 let pathname = url.pathname
 // 通過路由判斷,只有首頁才進行緩存
 if (['/home'].indexOf(pathname) > -1) {
 const existsHtml = cachePage.get('homeData')
 if (existsHtml) {
 return res.end(existsHtml.html, 'utf-8')
 } else {
      res.original_end = res.end
 // 重寫res.end
      res.end = function (data) {
 if (res.statusCode === 200) {
 // 設置緩存
         cachePage.set('homeData', { html: data})
 }
 // 最終返回結果
        res.original_end(data, 'utf-8')
 }
 }
 }
 next()
}

nuxt.config.js配置項修改,引入服務端中間件

//針對home路由做緩存
serverMiddleware: [
 { path: '/home', handler: '~/middleware/page-cache.js' },
]

 

原始鏈接: https://zhuanlan.zhihu.com/p/67877406


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM