日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

基于Vue-SSR优化方案归纳总结

發布時間:2024/2/28 vue 78 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于Vue-SSR优化方案归纳总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Vue-SSR相信大家都不陌生,與傳統 SPA 相比,服務器端渲染 (SSR) 能夠具備更好的SEO,方便搜索引擎爬蟲抓取工具可以直接查看完全渲染的頁面,除此之外,SSR能夠在更短的時間內渲染出頁面內容,通過在服務端填充數據吐出到客戶端的方式,讓用戶有更好的用戶體驗。前言基于VueSSR的頁面優化常有,而針對VueSSR的再優化不常有。前段時間有幸作為宇宙無敵上級特派看門員參加了前端tweb大會,聽取了騰訊視頻Web高級工程師lucien(段隆賢) 分享了針對SSR場景下的一些優化,由于筆者之前也有在項目中實現SSR渲染,所以也針對Vue-SSR的優化進行了實踐和歸納總結,并且在前人的基礎上進行了新的優化嘗試,當然,不同的項目不同的場景下,優化效果、優化方案可能不盡相同,需要讀者們自行選取~(本文將討論常見的SSR優化方案以及筆者個人的優化嘗試)
CSR與SSR的區別首先,還是要不厭其煩地過一遍CSR和SSR的區別,在理清整個流程后,才能發現性能瓶頸以及關鍵耗時在哪里。
CSR一般由靜態資源服務器(CDN)等直接返回HTML資源,之后瀏覽器解析HTML加載CSS、JS資源(CSS加載結束后頁面會盡快進行首屏渲染FP),JS依賴加載結束后,Vue實例初始化,拉取頁面數據,頁面渲染(FMP)。
SSR由nodejs服務器來直出頁面,請求到達后端后,后端拉取cgi接口數據,根據直出bundle生成render對象,render對象將執行客戶端代碼構建VDOM,生成HTML string,填充進模板HTML,返回HTML資源,瀏覽器解析后加載CSS、JS資源,(在CSS加載結束后觸發FP和FMP),Vue實例初始化,接管后端直出的HTML,頁面可響應。

(以下流程圖引自:https://www.jianshu.com/p/10b6074d772c)

時序圖(注:FP即First paint,首屏渲染,可能是沒有數據的狀態。FMP即First meaningful paint,處于已經渲染數據的狀態。可交互:頁面數據填充結束且可響應。)

SSR存在的缺陷:

1、對服務器提出更高的要求,生成虛擬DOM如果相對較長的運行和計算耗時;2、由于cgi拉取和vdom直出后才吐出HTML頁面,FMP雖然提前了,但是FP相對延遲了;3、相比CSR,SSR渲染后,由于仍然需要進行依賴、vue初始化,頁面可交互時間并沒有較大改善。常見優化方法

雖然SSR仍有許多不足之處,但是也不是沒有改善的空間。

一、緩存優化

1、頁面級別緩存:vuessr官網給我們提供了一種方法,如果頁面并非千人千面,總是為所有用戶渲染相同的內容,我們可以利用名為 micro-caching 的緩存策略,來大幅度提高應用程序處理高流量的能力。這通常在 Nginx 層完成,也可以在 Node.js 中實現。

2、組件級別緩存:通過對組件設置serverCacheKey的方式,如果組件serverCacheKey相同,將復用之前渲染的組件產物,不需要重新渲染。具體是類似這樣的:export default {
name: 'myComponent', // 必填選項
props: ['item'],
serverCacheKey: props => props.item.id,
render (h) {
return h('div', this.item.id)
}
}3、cgi接口緩存:如果部分cgi接口返回的數據是固定的, 我們可以在node后端拉取cgi的時候,設置cgi緩存,緩存至memcache或其他輕量存儲服務,當然,你也需要設置好緩存更新策略。

二、代碼實現優化

1、減少組件嵌套層次,優化HTML結構:由于組件最初需要在node后端進行VDOM計算和渲染,優化組件層次結構,減少過深曾經的DOM嵌套,可以減少VDOM計算耗時。

2、減少首頁渲染數據量:根據業務調整用戶首屏可見的所需渲染的數據,其他數據懶加載或異步加載。

三、資源加載

1、流式傳輸:vuessr官網給我們介紹了一種方法,render對象會暴露renderToStream方法,把原有的直出結果以流的形式輸出,讓我們可以更快的響應數據到客戶端,能減少首屏渲染時間,更早開始加載頁面資源。(流式傳輸需要在asyncData執行結束后開始,否則沒有數據,這意味著流失傳輸受限于cgi拉取耗時)

2、分塊傳輸:lucien大佬在tweb大會上給我們帶來了新的思路,由模板的語法樹, 分析代碼的上下文,分析數據和模板間的依賴,用異步數據分割模板,分塊逐步輸出。(相比流式傳輸,前置位的cgi數據一旦ready,就會渲染輸出,而不需要等待所有的gi拉取到后才開始渲染輸出,但是該方案改造成本較大)

一張圖說明白這兩者的區別:

四、改造SSR算法

SSR算法改造:在tweb大會上lucien給我們介紹了一個新的思路,改造直出算法,不用vue-loader而用自研的aga-loader,將vdom渲染轉換為字符串模板,具有更高的渲染性能。

性能提高的同時,由于沒有完整的組件運行環境,也帶來了部分語法上的約束,同時,也不支持vuex。

思考

看到這里,讀者們應該對SSR了如如來神掌且熟悉了常見的優化方法,但是回頭思考一下,Vue-SSR的優化無非是在 cgi拉取 和 VDOM直出渲染 上下功夫,因為這兩者就是node后端最耗時的步驟,其次,由于這種耗時會同步阻塞頁面的FP,所以更進一步的方法是流式輸出或分塊,減少首屏渲染時間。

然而,但是并不是所有的cgi都能緩存,類似拉取用戶個人信息的cgi就無法緩存,SSR算法改造成本大,約束也大。再看看流式傳輸和分塊傳輸,兩者雖然都對FP時間優化了,但流式傳輸受限于cgi拉取時間,分塊傳輸改造成本大。而且兩者存在的一個共性問題,那就是可交互時間仍然沒有優化。

當然,這里并不是要否定所有的優化方法,而是方法各有優劣,比較優缺點大家才能根據自己的業務需求和優化場景選取合適的優化方法。受流式傳輸和分塊傳輸的啟發,我們能不能在這上面下功夫?在請求到來時,先返回一份完整的HTML空頁面,讓客戶端更快的FP,其次,后端拉取cgi和渲染VDOM 與?前端拉取CSS、JS資源?兩者同步進行,之后再吐出直出的HTML string 與 頁面store,再次渲染頁面,這樣的話FP提前了,和CSR的FP時間一毛一樣,其次,FMP相比CSR大大提高,更重要的是,由于JS資源的加載讓Vue初始化觸發的更早,意味著頁面可響應時間也會提高。

為了闡明這種區別,我們看一下流程圖:
新方案探索與實踐

先吐空頁面,之后再吐直出后的數據,但是關鍵是怎么讓直出后的數據再渲染上去,同時不要讓JS先執行了,導致頁面直接變成CSR了。

思考歷程:不要讓JS執行,等直出數據回來了再執行,這可咋辦,筆者最初想實現一個JS加載控制器,不通過script來引入js,而是自己去拉取js代碼,eval函數執行,這樣js的執行控制權就在自己手上了,但是有幾個問題,eval函數解析只是把字符串當js來執行,那錯誤上報就會出問題,接了sentry錯誤上報是基于js文件、錯誤行列來定位的,除此之外,ajax來拉取js代碼會不會存在性能問題,和瀏覽器加載js資源速度上是否存在差異?還有第三方js不能直接ajax拉取,需要設置跨域頭。于是筆者開始換一種思路,能不能給每個js文件包裹一層函數,通過setTimeout(fn,0)的方式來延遲調用,但是這又有問題,有多個js文件且文件已經是打包好了的,改了js文件,map映射不就亂了嗎?錯誤上報不就亂了嗎?

源碼在自己手里,為啥不直接在源碼上提供一個調用入口,來觸發js執行,最后直出的時候吐出<script>window.render()<script>來控制js執行不就可以了嗎?

開始改造

客戶端改造:

原有的直出存在entry-client和entry-server兩個js文件,分開兩個入口各自打包,我們需要改造的是entry-client,讓其可控制,開頭筆者只是對new App()和mount 包裹了一層函數,但是后來發現,第三方js依賴執行了,其實如果你明白webpack的打包原理,那么require的時候就會觸發相應的依賴執行,我們要在entry-client之外再包一層來控制。新增entry-runner文件:window.__GLOBAL_RENDER__ = function() {
require("./entry-client.js");
console.log("__GLOBAL_RENDER__ ENDING"); // eslint-disable-line
};

以這個為打包入口,加載完js后就不會執行了(當然,還會執行webpack的運行時代碼,控制chunk執行的,忽略不計)

改造服務端直出代碼:module.exports = functionhandle(req,res){
res.writeHead(200, {
'Content-Type': 'text/html',
});
res.write(FP_html.replace(/<\/body>[\s\S]*<\/html>/g,''));
// ...other code
}

FP_html是客戶端打包的時候生成的index.html,里面已經插入好了css、js依賴,你只需要把尾部body和html的結束標簽去掉。

接下來是在直出后吐出直出數據。constcontext = {
url: req.REQUEST.pathname
};
consthtml = awaitrenderToString(context);
consthtml_render = html.match(/(<div data-server-rendered[\s\S]*<\/div>)[\s\S]*(<script>window.__INITIAL_STATE__[\s\S]*injected -->)/g);
constinnerHTML = RegExp.$1;
conststate = RegExp.$2;
res.write(`
<script>
document.body.innerHTML = \`${innerHTML}\`
</script>
${state}
<script>
setTimeout(()=>{
window.__GLOBAL_RENDER__ && window.__GLOBAL_RENDER__()
},0)
</script>
</body>
</html>
`);
res.end();

通過正則提取出渲染結果html以及store,之后write吐會給前端,innerHTML會覆蓋第一次吐給前端的頁面中的div#app,接下來state即全局的store初始化,最后setTimeout控制window.__GLOBAL_RENDER__執行即可,因為vue判斷是否直出是根據div以及全局的store是否初始化來判斷的,所以我們這樣做沒有問題。其次,為了優先觸發一次FMP,我們需要通過setTimeout的方式調用全局渲染方法。

接下來我們來比較一下CSR、SSR以及改造后的效果:

CSR:

SSR:

優化后的SSR:各項數據對比:
類型\指標FPFMP可交互時間
CSR0.4s1.1s1.2s
SSR0.7s0.7s1s
優化SSR0.4s0.6-0.7s0.8s

可以明顯的看到,優化后的SSR,FP時間跟CSR一樣,讓我們的首屏渲染更快了(可優先渲染頁面骨架圖),其次,FMP時間跟SSR相差不大,最后是可交互時間,由于JS依賴較早開始加載,所以頁面直出結束后可馬上執行vue初始化邏輯,所以可交互時間縮短到0.8s。

我們找到了一種成本不是很高,不僅優化了FP、FMP時間還優化了可交互時間的方法!

最后

文章看到了這里,相信你對Vue-SSR有了更加深刻的認識和了解,本文比較了CSR和SSR,并總結歸納了Vue-SSR的常見方法,最后在新的方案上進行嘗試,達到了一定程度上的優化。優化方案各有優劣,也有成本開銷,根據自己業務需求來選擇合適的優化方法,才是最有效的。希望本文能給你帶來幫助~ 也歡迎討論其他方法~

總結

以上是生活随笔為你收集整理的基于Vue-SSR优化方案归纳总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。