1. 程式人生 > >Nuxt 專案效能優化調研

Nuxt 專案效能優化調研

效能優化,這是面試中經常會聊到的話題。我覺得效能優化應該因具體場景而異,因不同專案而異,不同的手段不同的方案並不一定適合所有專案,當然這其中不乏一些普適的方案,比如耳熟能詳的檔案壓縮,檔案快取,CDN,DNS 預解析,等等,但是我更希望聽到的是因為不同的專案不同的需求,解決不同的問題而採取的不同的優化手段,比如 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 上下,平均響應時長七八秒,所以卡是正常現象 看了一下專案程式碼,發現了幾個問題: 1. 專案沒做快取,所以每次訪問都會經歷所有 Nuxt 生命週期,消耗 cpu,這點是最致命的 2. 專案打包預設 gzip。Nuxt 專案打包會預設在服務端開啟 gzip,因為我們閘道器層已經做了 gzip,所以這裡是不必要的,測試了下關掉 gzip 吞吐量和響應時間都能提高 20% 左右 3. API 請求比較亂。很多請求並沒有很好地區分客戶端和服務端,而是都由服務端去做了,造成服務端壓力過大,其實多數和使用者有關的請求理應放到客戶端。有的介面為了方便,一次性返回了所有內容,也沒有做客戶端/服務端區分。另外,服務端的介面請求可以併發,用類似 Promise.all 的形式去控制 4. SEO。有的內容頁面,很長,有五個部分,除了內容外,還有猜你喜歡等其他部分,詢問了 SEO 同事,說這幾部分都是需要 SEO 的,我不是很懂 SEO,但是在我看來,ssr 只應該渲染首屏內容,而 UI 在設計的時候應該把主要內容設計到首屏,從而滿足 SEO 對此我覺得可以從兩個方向去優化: 1. 快取。快取是最重要的方案,針對 Nuxt 專案可以做三級快取,頁面快取、元件快取以及 API 快取。頁面快取是最重量級的快取方案,能不能做頁面快取可以從以下兩個點判斷: * 同一個 URL,對於 登入 / 非登入 使用者,服務端渲染的內容是相同的(注意是服務端渲染內容,而非前端) * 同一個 URL,對於不同的登入使用者,服務端渲染的內容是相同的,即沒有一些個性化的渲染(常見的個性化渲染,比如針對不同使用者渲染不同的猜你喜歡內容等) 其實也就是返回的 html 程式碼相同就好,主要關注下返回的全域性 store 是否一致,另外也不能做一些服務端才能做的操作,比如 set-cookie 等 2. 控制好首屏模組個數,對返回的結果進行精簡,最小化,保證吐出到瀏覽器的內容足夠小。這就是前面說的並不要對所有模組都做 ssr,需要首屏呈現的/需要爬蟲爬的,我們直出,其他部分做 CSR 就行了 而我們的網站大部分頁面是滿足做頁面快取條件的,測試了下如果做頁面快取,吞吐量能到 500+,這個資料這個時候其實是和頁面大小有關係了,頁面快取的效能是能滿足需求的。而有另一類頁面,相同的 URL 會返回不同的內容,而且整頁都是不同內容,它的實現是獲取 cookie 中的不同 city-id,渲染不同城市的內容,很顯然這部分頁面做不了頁面快取了,API 快取和元件快取理論上都是可以試試的 做快取優化,至少需要訪問一次,第二次才能生效,那麼還有另一種情況,對於這樣的路由 `/store/:id`,併發開啟 id 0~1000,很顯然每個頁面都是不一樣的店鋪資料,並不能命中快取(可能命中元件快取,暫時忽略),這個時候只能從 Nuxt 生命週期上去優化了,那麼以上方向的第二點,控制首屏模組個數就能用到了。所以本文一開始我就說,不同的方案是適配不同的場景的,解決不同的問題會採取不同