Nuxt 項目性能優化調研

性能優化,這是面試中常常會聊到的話題。我以爲性能優化應該因具體場景而異,因不一樣項目而異,不一樣的手段不一樣的方案並不必定適合全部項目,固然這其中不乏一些普適的方案,好比耳熟能詳的文件壓縮,文件緩存,CDN,DNS 預解析,等等,可是我更但願聽到的是由於不一樣的項目不一樣的需求,解決不一樣的問題而採起的不一樣的優化手段,好比 BigPipe,分段輸出頁面的各個部分,對於 SNS 網站是很是合適的,減小了用戶的等待時間;相對應的還有一個 BigRender,這是一個大的延遲加載,360 導航首頁目前還在使用,京東淘寶首頁也是這個思路,對於一些類門戶網站很是適用,可是若是你的網頁內容不是很是多,就沒有必要了html

今天要說的是 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,這就決定了高流量項目並不會輕易去使用 Nuxtwebpack

咱們的項目目前實際上是一個不加優化的 Nuxt 項目,由於用戶很少,平時並無什麼問題,可是一到展會,就會有很多用戶同時訪問,反饋頁面會很卡。同條件下作了壓測後,吞吐量也是 50 上下,平均響應時長七八秒,因此卡是正常現象web

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

  1. 項目沒作緩存,因此每次訪問都會經歷全部 Nuxt 生命週期,消耗 cpu,這點是最致命的
  2. 項目打包默認 gzip。Nuxt 項目打包會默認在服務端開啓 gzip,由於咱們網關層已經作了 gzip,因此這裏是沒必要要的,測試了下關掉 gzip 吞吐量和響應時間都能提升 20% 左右
  3. API 請求比較亂。不少請求並無很好地區分客戶端和服務端,而是都由服務端去作了,形成服務端壓力過大,其實多數和用戶有關的請求理應放到客戶端。有的接口爲了方便,一次性返回了全部內容,也沒有作客戶端/服務端區分。另外,服務端的接口請求能夠併發,用相似 Promise.all 的形式去控制
  4. SEO。有的內容頁面,很長,有五個部分,除了內容外,還有猜你喜歡等其餘部分,詢問了 SEO 同事,說這幾部分都是須要 SEO 的,我不是很懂 SEO,可是在我看來,ssr 只應該渲染首屏內容,而 UI 在設計的時候應該把主要內容設計到首屏,從而知足 SEO

對此我以爲能夠從兩個方向去優化:express

  1. 緩存。緩存是最重要的方案,針對 Nuxt 項目能夠作三級緩存,頁面緩存、組件緩存以及 API 緩存。頁面緩存是最重量級的緩存方案,能不能作頁面緩存能夠從如下兩個點判斷:瀏覽器

    • 同一個 URL,對於 登陸 / 非登陸 用戶,服務端渲染的內容是相同的(注意是服務端渲染內容,而非前端)
    • 同一個 URL,對於不一樣的登陸用戶,服務端渲染的內容是相同的,即沒有一些個性化的渲染(常見的個性化渲染,好比針對不一樣用戶渲染不一樣的猜你喜歡內容等)

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

  2. 控制好首屏模塊個數,對返回的結果進行精簡,最小化,保證吐出到瀏覽器的內容足夠小。這就是前面說的並不要對全部模塊都作 ssr,須要首屏呈現的/須要爬蟲爬的,咱們直出,其餘部分作 CSR 就好了性能優化

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

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

相關文章
相關標籤/搜索