中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何優化Nuxt 項目的性能

發布時間:2020-11-07 15:58:04 來源:億速云 閱讀:2193 作者:Leah 欄目:開發技術

如何優化Nuxt 項目的性能?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

性能優化,這是面試中經常會聊到的話題。我覺得性能優化應該因具體場景而異,因不同項目而異,不同的手段不同的方案并不一定適合所有項目,當然這其中不乏一些普適的方案,比如耳熟能詳的文件壓縮,文件緩存,CDNDNS 預解析,等等,但是我更希望聽到的是因為不同的項目不同的需求,解決不同的問題而采取的不同的優化手段,比如 BigPipe,分段輸出頁面的各個部分,對于 SNS 網站是非常合適的,減少了用戶的等待時間;相對應的還有一個 BigRender,這是一個大的延遲加載,360 導航首頁目前還在使用,京東淘寶首頁也是這個思路,對于一些類門戶網站非常適用,但是如果你的網頁內容不是非常多,就沒有必要了

今天要說的是 Nuxt。Nuxt 是支持 Vue SSR 的一個框架,底層需要運行 Node 服務。大概描述一下 Vue 的渲染過程,首先每個組件都會被編譯生成一個渲染函數(這部分基本 webpack 打包已經做掉),然后渲染函數生成虛擬 dom,最后虛擬 dom 通過 patch 方法將真實 dom 渲染到頁面上。Nuxt 其實就是將這部分放到了服務端去做,在服務端拿到渲染頁面所需要的 html,從而使得 html 能夠直出,而客戶端其實還是會運行整個 Vue 的生命周期,這就帶來了一個問題,這部分操作放在了服務端其實是非常耗 cpu 的,創建組件實例和虛擬 DOM 節點的開銷,無法與純基于字符串拼接的模版的性能相當,如果是不加優化的 Nuxt 項目,高并發下是很脆弱的,畢竟 Node 運行在單線程下,不適合 cpu 操作密集型的場景

使用 Nuxt 的項目無非看中了它的兩大優點,一是服務端渲染滿足 SEO 的需求,二是首屏直出比 SPA 快,再加上如果如果公司是 Vue 系,使用 Nuxt 就更順理成章。但是不要忘了性能,高并發下 Nuxt 性能確實不樂觀,我測試了官網的 hackernews demo 項目,2 核 cpu + 4g 內存,400 并發下它的吞吐量不超過 50,就算是最簡的 Nuxt 項目,吞吐量也就 300+,這就說明如果項目不做緩存,300+ 已經是最大的吞吐量了,而最小 express demo 可以輕松到 3000,這就決定了高流量項目并不會輕易去使用 Nuxt

我們的項目目前其實是一個不加優化的 Nuxt 項目,因為用戶不多,平時并沒有什么問題,但是一到展會,就會有不少用戶同時訪問,反饋頁面會很卡。同條件下做了壓測后,吞吐量也是 50 上下,平均響應時長七八秒,所以卡是正常現象

看了一下項目代碼,發現了幾個問題:

項目沒做緩存,所以每次訪問都會經歷所有 Nuxt 生命周期,消耗 cpu,這點是最致命的

項目打包默認 gzip。Nuxt 項目打包會默認在服務端開啟 gzip,因為我們網關層已經做了 gzip,所以這里是不必要的,測試了下關掉 gzip 吞吐量和響應時間都能提高 20% 左右。具體做法是在 nuxt.config.js 中配置(還是得看 英文文檔,會告訴你如何不設置 To disable compression, use compressor: false,中文文檔當時三月份我寫這文的時候還沒加這個選項,而目前中文文檔也沒有翻譯這一句 2020-07-16)

render: {
 compressor: false
}

API 請求比較亂。很多請求并沒有很好地區分客戶端和服務端,而是都由服務端去做了,造成服務端壓力過大,其實多數和用戶有關的請求理應放到客戶端。有的接口為了方便,一次性返回了所有內容,也沒有做客戶端/服務端區分。另外,服務端的接口請求可以并發,用類似 Promise.all 的形式去控制

SEO。有的內容頁面,很長,有五個部分,除了內容外,還有猜你喜歡等其他部分,詢問了 SEO 同事,說這幾部分都是需要 SEO 的,我不是很懂 SEO,但是在我看來,ssr 只應該渲染首屏內容,而 UI 在設計的時候應該把主要內容設計到首屏,從而滿足 SEO

對此我覺得可以從兩個方向去優化:

緩存。緩存是最重要的方案,針對 Nuxt 項目可以做三級緩存,頁面緩存、組件緩存以及 API 緩存。頁面緩存是最重量級的緩存方案,能不能做頁面緩存可以從以下兩個點判斷:

同一個 URL,對于 登錄 / 非登錄 用戶,服務端渲染的內容是相同的(注意是服務端渲染內容,而非前端)

同一個 URL,對于不同的登錄用戶,服務端渲染的內容是相同的,即沒有一些個性化的渲染(常見的個性化渲染,比如針對不同用戶渲染不同的猜你喜歡內容等)

其實也就是返回的 html 代碼相同就好,主要關注下返回的全局 store 是否一致,另外也不能做一些服務端才能做的操作,比如 set-cookie 等

控制好首屏模塊個數,對返回的結果進行精簡,最小化,保證吐出到瀏覽器的內容足夠小。這就是前面說的并不要對所有模塊都做 ssr,需要首屏呈現的/需要爬蟲爬的,我們直出,其他部分做 CSR 就行了

而我們的網站大部分頁面是滿足做頁面緩存條件的,測試了下如果做頁面緩存,吞吐量能到 500+,這個數據這個時候其實是和頁面大小有關系了,頁面緩存的性能是能滿足需求的。而有另一類頁面,相同的 URL 會返回不同的內容,而且整頁都是不同內容,它的實現是獲取 cookie 中的不同 city-id,渲染不同城市的內容,很顯然這部分頁面做不了頁面緩存了,API 緩存和組件緩存理論上都是可以試試的

做緩存優化,至少需要訪問一次,第二次才能生效,那么還有另一種情況,對于這樣的路由 /store/:id,并發打開 id 0~1000,很顯然每個頁面都是不一樣的店鋪數據,并不能命中緩存(可能命中組件緩存,暫時忽略),這個時候只能從 Nuxt 生命周期上去優化了,那么以上方向的第二點,控制首屏模塊個數就能用到了。所以本文一開始我就說,不同的方案是適配不同的場景的,解決不同的問題會采取不同的手段

補充知識:Nuxt實現的SSR頁面性能優化的進一步探索與實踐

前言

本文之前,先簡單介紹以下幾個概念:

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項目,需要感興趣的各位自行查看官方文檔及自我實踐了,本文不做贅述。

探索與實踐

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

一、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' }, 
]

關于如何優化Nuxt 項目的性能問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

西藏| 西吉县| 长泰县| 梧州市| 赣州市| 湖南省| 城口县| 宁阳县| 抚宁县| 吉木萨尔县| 九龙县| 滕州市| 涿州市| 特克斯县| 邻水| 高台县| 甘孜县| 五台县| 北流市| 阿巴嘎旗| 咸丰县| 交城县| 安化县| 沁源县| 海门市| 滨海县| 全椒县| 璧山县| 越西县| 堆龙德庆县| 嘉善县| 辉南县| 康平县| 富宁县| 十堰市| 隆尧县| 堆龙德庆县| 丹巴县| 滨海县| 彭山县| 资讯|