能讓你縱享絲滑的SSR技術,轉轉這樣實踐

大家好,我是若川(點這里加我微信?ruochuan12,長期交流學習)。今天推薦這篇圖文并茂的SSR技術文章。這是江西前端群里一個小伙伴的文章。群里小伙伴很多都在知名大廠,但他們都很低調。

點擊下方卡片關注我、加個星標,或者查看源碼等系列文章。學習源碼整體架構系列、年度總結、JS基礎系列


SSR最佳實踐

秒開率對于用戶的留存率有直接的影響,數據表明, 網頁加載時間過長會直接導致用戶流失.轉轉集團作為一家電商公司, 對于H5頁面的秒開率有著更加嚴格的需求, 在主要的賣場側頁面(手機頻道頁、3c頻道頁、活動頁)等重要流量入口我們都采用了SSR(服務端渲染)技術來構建頁面,今天就帶大家了解一下我們摸索出來的一些最佳實踐.

網頁的前世今生

在早期的web應用中,實際上我們都是用的服務端渲染技術, 像jsp、asp、php等各種后臺模板生成的頁面,前端都是拿到整張頁面,不用自己去拼接DOM.后來隨著前后端分離開發模式,衍生出了最主要的兩種渲染方式CSR以及SSR.

  • CSR : 客戶端渲染,整個渲染流程是: ?瀏覽器請求url --> 服務器返回index.html(空body、白屏) --> 再次請求bundle.js、路由分析 --> 瀏覽器渲染bundle.js體積越大, 就會導致白屏的時間越長,給用戶的體驗就越差(當然,這可以借助打包構建工具來優化這部分)

    交互流程圖如下

圖1-1客戶端渲染流程圖
  • SSR : 服務端渲染, ?服務端渲染分為兩個步驟:

  • 階段一: ?瀏覽器請求url --> 服務器路由分析、執行渲染 --> 服務器返回index.html(實時渲染的內容,字符串) --> 瀏覽器渲染 ?(此時是一個靜態頁面, 不可交互, 依賴于服務端的能力, 這就是快的原因)

  • 階段二:瀏覽器請求bundle.js --> 服務器返回bundle.js --> 瀏覽器路由分析、生成虛擬DOM --> 比較DOM變化、綁定事件 --> 二次渲染 (用戶可交互)

我們來看看整個交互流程圖 :

圖 1-2 服務端渲染交互流程圖

SSR構建邏輯

理解了兩種渲染模式的異同,我們來看看SSR整個構建邏輯(主要以Vue-SSR為例)

我們以官網的圖片為例:

圖 2-1 SSR構建邏輯

從圖中我們可以知道 :

在整個構建過程中, 我們有兩個入口, 一個是server-entry.js, 執行server端的邏輯, 一個是client.js, 執行client端的邏輯, 然后通過會將webpack打包分成兩個Bundle: 服務端bundle; 客戶端bundle. Node.js會處理服務端bundle用于SSR, 客戶端bundle會在用戶請求時和已經由SSR渲染出的頁面一起返回給用戶, 然后在瀏覽器執行”注水”(hydrate), 接管Vue接下來的業務邏輯.

理解了整個構建邏輯,接下來我們來看看我們是怎么運用SSR來服務我們的項目的.

SSR構建項目的背景

賣場側業務首頁組成大同小異: 主要分首屏和第二屏, 首屏有多個模塊組成, 第二屏是商品Feed流,便于讀者理解, 我們抽象出了頁面結構圖:

圖 2-2 頁面結構圖

(歡迎大家下載轉轉app體驗)

而且這些頁面都有一個共同的特點:

  • 只用于展示, 和用戶的狀態不強綁定(不需要用戶登錄)

  • 頁面狀態穩定,內容不會經常變更

  • 都是重要流量的第一個入口(首頁)

由于對于秒開率有著極高的要求,又承載了主要流量入口,結合以上頁面特點,所以我們使用了SSR來提升用戶體驗.

經過一系列的探索和探究, 我們最終使用Nuxt.js來作為我們的技術選型.

這里提下為啥使用Nuxt.js作為我們的技術選型, 主要原因有以下幾點:

  1. 集團內部C端業務是以Vue技術棧為主,B端技術棧是以React為主, 所以不考慮React服務端渲染技術棧;

  2. Nuxt.js是開箱即用的服務端渲染框架,不用開發人員自己去搭建Vue+ Vue-server-renderer + vuex來集成服務端渲染框架, 接入成本比較低.

SSR運用的最佳實踐

目前我們使用SSR實現的主要能力有:

  • 首屏使用服務端渲染,第二屏使用客戶端渲染,首屏模塊數據可調整,即優化了性能, 又豐富了頁面配置.

  • 合理化使用緩存, 進一步提升用戶體驗.

  • 實現css注入,達到按需換膚的效果.

  • 使用ErrorBoundary攔截錯誤,使得組件錯誤不會影響整個頁面白屏.

  • 按需加載第二屏數據,只有滑動到可見范圍, 才加載第二屏數據

  • 針對大促場景, 結合服務端能力, 以及各種監控,docker擴容,保證頁面穩定.

接下來就和大家探索其中幾種能力的主要思路:

怎樣實現首屏使用服務端渲染,第二屏使用客戶端渲染

這種實現方式主要是結合asyncData在服務端異步獲取數據,使用vue動態組件component的特性,來調整模塊的渲染順序; mounted生命鉤子只會在客戶端執行, 使用僅在客戶端渲染組件的特性來實現的.

示例代碼:

<template><!--服務端渲染,動態獲取首屏模塊并且加載對應模塊的數據,?使用error-boundary來攔截錯誤--><template?v-for="(e,?i)?in?structureOrder"><error-boundary><component?:info="activityState.structure[e]":is="Mutations.name2Component(e)"class="anchor":id="e":key="i"?:name="e"?v-if="activityState.structure[e]?||?e?===?'bar'?"/></error-boundary></template><!--客戶端渲染--><client-only><!--滑動到可見范圍加載對應的數據--><div?:is="listComponent"?:tab="labelFilter"/></client-only>
</template>

獲取數據:

//服務端渲染數據
async?asyncData({app,?route,?req})?{const?initData?=?await?app.$axios.$get(host,?{params:?{name:?key,?from,?smark,?keys:?`structure,base,labelFilter,navigate,redPack,${elements}`},?headers})const?{structureInfo,?structureOrder,?restStructure,?anchors}?=?Mutations.initStructure(initData)return?{structureInfo,restStructure,structureOrder,?//動態返回對應模塊的名稱useVideo:?Mutations.checkUseVideo(req),theme,pageFrom:?route.query.from,isPOP,anchors,...formInfo}
},
async?mounted()?{//獲取客戶端渲染的數據const?res?=?await?this.initData()
},

怎樣使用ErrorBoundary捕獲組件級別錯誤,避免整個頁面白屏

關于ErrorBoundary這個捕獲錯誤的組件,這個組件的主要功能是使得組件級的錯誤不會蔓延到頁面級,不會造成整個頁面的白屏,考慮到服務端渲染可能會發生偶發性錯誤,狀態容易變的不可控, 所以使用這個能力還是很有必要的, 這個組件主要使用vue提供的 errorCaptured 來捕獲組件級的錯誤, 想詳細了解這個api的作用可以去看官方文檔,具體的實現如下:

const?errorBoundary?=?Vue?=>?{Vue.component('ErrorBoundary',?{data:?()?=>?({?error:?null?}),errorCaptured(err,?vm,?info)?{this.error?=?`${err.stack}\n\nfound?in?${info}?of?component`SentryCapture(err,?1)?//異常上報到sentryreturn?false},render()?{return?(this.$slots.default?||?[null])[0]?||?null}})
}//?全局注冊errorBoundary
Vue.use(errorBoundary)

怎樣實現css注入,實現頁面換膚

這個功能的主要作用是 : 可以根據配置json文件定制化活動頁面的樣式, 做到"千人千面" (一個會場的key可以配置一種樣式, 但是底層代碼是一套),使得元素多樣化,在視覺上給用戶體驗帶來很大提升.

我們先來看看效果示意圖:

以上就是展示效果, 借住CSS注入, 我們可以根據不同的json文件來定制化頁面的樣式, 只需要維護一套代碼, 簡單高效.

實現邏輯也很簡單,主要是運用了Nuxt.js框架提供的head方法:

head()?{//this.baseInfo.additionStyle是從json文件拿到的樣式//通過css權重,?可以實現樣式覆蓋return?{style:?[{cssText:?this.baseInfo?.additionStyle?||?'',?type:?'text/css'}],__dangerouslyDisableSanitizers:?['style']??//?防止對一些選擇器的特殊字符進行轉義}},

不僅如此, 還可以實現js注入, 感興趣的小伙伴可以自己去了解,底層原理可以了解下 vue-meta 這個庫

但是, 隨著業務的不斷迭代, 這種注入方式還是存在很多可優化的點:

  • 每個活動頁運營同學都要維護一份json文件,里面包含冗長的css配置字段, 活動規則等等, 特別是css配置字段,就是一段冗長的css, 給運營和開發同學帶來很大的不便;

  • 運營同學維護成本高,學習成本高,操作成本高;

  • 對于UI同學成本也大, 每次都需要UI同學來設計活動頁面樣式;

目前, 集團內部正在使用 魔方 一步一步去替代這種方式, 魔方 只需要運營同學拖拖拽拽, 就能生成一個活動頁, 簡單高效, 想要了解魔方的同學, 可以繼續關注我們的公眾號

怎樣實現組件滑動到可見范圍,才加載數據

其實這種優化頁面的方法并不是說只適用于SSR, 其他非SSR頁面也可以使用這種方式來優化;

看看我們的實現方式 :

function?asyncComponent({componentFactory,?loading?=?'div',?loadingData?=?'loading',?errorComponent,?rootMargin?=?'0px',retry=?2})?{let?resolveComponent;return?()?=>?({component:?new?Promise(resolve?=>?resolveComponent?=?resolve),loading:?{mounted()?{const?observer?=?new?InterpObserver(([entries])?=>?{if?(!entries.isIntersecting)?return;observer.unobserve(this.$el);let?p?=?Promise.reject();for?(let?i?=?0;?i?<?retry;?i++)?{p?=?p.catch(componentFactory);}p.then(resolveComponent).catch(e?=>?console.error(e));},?{root:?null,rootMargin,threshold:?[0]});observer.observe(this.$el);},render(h)?{return?h(loading,?loadingData);},},error:?errorComponent,delay:?200});
}export?default?{install:?(Vue,?option)?=>?{Vue.prototype.$loadComponent?=?componentFactory?=>?{return?asyncComponent(Object.assign(option,?{componentFactory}))}}
}

實現原理主要是使用vue高階組件, 元素到達可見范圍內, 延遲加載組件;

看看效果圖:

我們可以看到,只有到底部商品Feed流出現在可視范圍,才去請求對應的接口

針對大促場景怎樣保證頁面穩定

所謂大促場景,是指像 6.18, 雙11,這種場景下, 面對大流量, 如何保證頁面穩定? SSR是CPU密集型任務, 意味著很耗費服務器資源,集團目前主要采取的策略是:

  • 對接口進行壓測, 模擬高并發場景下頁面性能, 接口響應速度;

  • 集團內部實現了一套監控系統, 可以實時監控CPU,內存的消耗情況;

  • 需要有服務器擴容方案, 比如接入docker, 可以實現服務器實時擴容

怎樣利用緩存

請大家移步集團一位前端大佬寫的公眾號文章: Nuxt實現的SSR頁面性能優化的進一步探索與實踐

最終,看看我們最終的實現效果:

可以看到, 首屏渲染時間在594ms, 秒開率在百分之87左右;

SSR的不足

ssr的使用過程并不是一帆風順的, 在使用的過程中, 也總結幾點不足之處:

  • 對于開發人員的要求更高, 要學習其他的額外知識,例如: Linux , node相關知識, 需要具備一定的后端思維;

  • 服務端渲染接口抓包不方便, 我們在客戶端抓取不到服務端的接口請求, 不過對于使用Mac電腦開發的同學,可以使用 proxychains-ng 來抓取服務端請求的接口

  • 冗長的配置環境過程, 每次開發聯調需要配置后端host

  • 對于服務器資源有要求,并發量越大, 資源消耗的越多

  • 服務端渲染可能會發生偶發性錯誤, 需要有一套降級方案

至于如何取舍, 看各位同學的項目需求,以及運用場景;

總結

SSR的使用有利有弊, 我們應該結合自己的業務特性去制定合適的方案, 它的優點就是快, 有利于SEO, 缺點也很明顯, 比較耗費服務器資源, 對于億級流量的超巨app來說, 理論上是不太合適的, 集團內部也有自己的一套方案來優化客戶端渲染, 使得用戶體驗盡量向SSR靠齊.每一種技術的運用只有實踐了才知道利弊,才能產生碰撞. 本文只是簡單的帶大家了解一條業務線上對SSR的運用, 所闡述的方面也只是冰山一角, 希望給廣大開發者帶來一定的啟發, 前人栽樹, 后人乘涼, 感謝轉轉FE前輩們留下的寶貴財富.

參考資料

nuxt官網: ?https://www.baidu.com/link?url=xy0d8KPUgTmiVoGge6g-FgdeqjJSTjxdpT0tpxZzBG_&wd=&eqid=db50cacf00052e5e000000066081587d

Vue SSR指南: https://ssr.vuejs.org/zh/guide/


最近組建了一個江西人的前端交流群,如果你也是江西人可以加我微信 ruochuan12 拉你進群。


·················?若川出品?·················

今日話題

寫篇原創優質文章不容易,寫了文章特別希望讓更多人看到,寫過文章的都懂。就像我現在每篇文章都帶上源碼系列鏈接,也是希望更多人看到。江西前端群里小伙伴寫了這篇文章,我連忙聯系開了白名單轉載。公眾號平臺保護原創作者權益非常好,如果你看到一篇文章被轉載多次,大概率說明這篇文章確實不錯。歡迎分享、收藏、點贊、在看我的公眾號文章~

一個愿景是幫助5年內前端人走向前列的公眾號

可加我個人微信 ruochuan12,長期交流學習

推薦閱讀

我在阿里招前端,我該怎么幫你?(現在還能加我進模擬面試群)

若川知乎問答:2年前端經驗,做的項目沒什么技術含量,怎么辦?

點擊方卡片關注我、加個星標,或者查看源碼等系列文章。
學習源碼整體架構系列、年度總結、JS基礎系列

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275959.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275959.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275959.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

魅族魅藍mirror簡單打開usb調試模式的步驟

經常我們使用安卓手機鏈接電腦的時候&#xff0c;或者使用的有些應用比如我們企業營銷團隊經常使用的應用引號精靈&#xff0c;以前使用的老版本就需要開啟USB調試模式下使用&#xff0c;現經常新版本不需要了&#xff0c;如果手機沒有開啟USB調試模式&#xff0c;電腦則無辦法…

hp-ux 單用戶 啟動_UX備忘單:搜索與瀏覽

hp-ux 單用戶 啟動重點 (Top highlight)When designing search results and interest sites, you have to keep in mind what ‘mode’ your user is in. Are they in ‘searching mode’ or ‘browsing mode’? This will help you determine how to design your platform to…

細數開源歷史上的九個重大事件

開放源碼&#xff08;開源&#xff09;的精神在于使用者可以使用、復制、散布、研究和改進軟件。這可以追溯到20世紀60年代&#xff0c;至今已有半個世紀了。伯樂在線-職場博客的這篇文章將列舉開源歷史上的九大重要事件。雖然本文不是專門對開源產品&#xff0c;但還是說到了一…

有贊大數據平臺安全建設實踐

一、概述 在大數據平臺建設初期&#xff0c;安全也許并不是被重點關注的一環。大數據平臺的定位主要是服務數據開發人員&#xff0c;提高數據開發效率&#xff0c;提供便捷的開發流程&#xff0c;有效支持數倉建設。大數據平臺的用戶都是公司內部人員。數據本身的安全性已經由公…

請先設置tkk_理光MP2014掃描至文件夾的設置方法

理光旗下的2014系列入門級A3黑白復印機市場保有量較大&#xff0c;該系列機型加裝M16網卡后可以方便的實現掃描至文件夾功能&#xff0c;經常有客戶咨詢該機型的掃描設置方法&#xff0c;下面我就以MP2014D為例來演示一下該機型的SMB掃描設置方法&#xff1a;首先是在電腦上建立…

聽說現在都考這些React面試題

大家好&#xff0c;我是若川。最近刷脈脈看見圈里都在聊面試&#xff0c;吐槽最多的還是萬年考點 React 和 Vue。不過關于兩者的比較似乎有點針尖對麥芒的趕腳。確實&#xff0c;面試的偏重點往往映射公司對該框架的重視程度&#xff0c;但也不能一概而論&#xff0c;去學習或放…

開發中的問題——環境相關

開始了解Android差不多兩周了&#xff0c;作為一名.net開發者&#xff0c;首次接觸Java類的技術&#xff0c;免不了會碰到一些問題&#xff0c;開博的第一篇就來說說自己遇到的問題以及一些感受。關于Android開發環境的搭建&#xff0c;網上已經有很多&#xff0c;其實等更新完…

荒島余生為什么沒有打開包裹_您會帶到荒島什么辦公桌設置?

荒島余生為什么沒有打開包裹Throughout life, you experience a lot of desks and a lot of desk setups. Real or virtual, at the office or at home, temporal or permanent — just a way to call it, nothing is permanent— a big one with a great office view or a sma…

c++ 整數取反_c++ 取反運算符“~”

取反符將二進制表示的數字中的0變為1, 1變為0但是需要注意的是c中對int型進行取反操作時&#xff0c;將前面的前導0也進行了取反(int型變量為32bit)。比如1的二進制表示是00000000 00000000 00000000 00000001~(00000000 00000000 00000000 00000001) 11111111 11111111 11111…

第五課 路由之初識路由

1.路由快速入門 1.1 概念 是指把數據從一個地方傳送到另一個地方的行為和動作&#xff0c;而路由器&#xff0c;正是執行這種行為動作的機器。它的英文名稱為Router&#xff0c;是一種連接多個網絡或者網段的網絡設備&#xff0c;它能將不同網絡或者網段之間的數據信息進行“翻…

Console Snacks[摘自Advanced Rails Recipes]

1. Write Console Methods在~/.irbrc定義ActvieRecord::Base.connection.select_all方法1.# ~/.railsrc2.def sql(query)3.ActiveRecord::Base.connection.select_all(query)4.end1.# ~/.irbrc2.if ENV[RAILS_ENV]3.load File.dirname(__FILE__) /.railsrc4.end這樣就可以在直…

如何使用 React 和 React Hooks 創建一個天氣應用

大家好&#xff0c;我是若川&#xff08;點這里加我微信 ruochuan12&#xff0c;長期交流學習&#xff09;。今天推薦一個練手的React項目&#xff0c;創建天氣應用&#xff0c;相信很快能看完。昨天發送書掉粉18人&#xff0c;是我沒想到的&#xff0c;送書一般是出版社按閱讀…

擬態防御_純素食漢堡的擬態

擬態防御If people are so against the idea of pigs and chickens being chopped up why would they want to buy fake bacon with realistic visual streaks of pork fat, or soy meat that tries to replicate the streaky texture of cooked chicken flesh? Surely these …

delphi 算術溢出解決方法_性能優化系列:JVM 內存劃分總結與內存溢出異常詳解分析...

前言那些使用過 C 或者 C 的讀者一定會發現這兩門語言的內存管理機制與 Java 的不同。在使用 C 或者 C 編程時&#xff0c;程序員需要手動的去管理和維護內存&#xff0c;就是說需要手動的清除那些不需要的對象&#xff0c;否則就會出現內存泄漏與內存溢出的問題。如果你使用 J…

微信小程序如何發送 http 請求

2019獨角獸企業重金招聘Python工程師標準>>> 為什么要使用云函數發送 http 請求小程序云函數5 個可信域名不受限制需要備案無需備案在一些特殊情境, 比如域名沒有備案或域名 5 個以上就需要使用云函數發送 HTTP 請求了. 如何使用云函數發送 HTTP 請求? 在云函數中能…

H5 頁面列表緩存方案

大家好&#xff0c;我是若川&#xff08;點這里加我微信 ruochuan12&#xff0c;長期交流學習&#xff09;。今天給大家介紹一下關于h5頁面的列表緩存方案。感謝屏幕前的你一直關注著我。點擊下方卡片關注我、加個星標&#xff0c;或者查看源碼等系列文章。學習源碼整體架構系列…

SQL未能排它地鎖定數據庫以執行該操作解決

SQL未能排它地鎖定數據庫以執行該操作解決&#xff1a; --原因其他用戶或進程在用著數據庫 /* 關閉用戶打開的進程處理 */ use master if exists (select * from dbo.sysobjects where id object_id(N[dbo].[p_killspid]) and OBJECTPROPERTY…

不只是coding_不只是外表

不只是coding“We just need it to look more professional…”“我們只需要看起來更專業...” “We don’t have the graphic expertise you do…”“我們沒有您所需要的圖形專業知識……” “I just don’t know how to make it look good…”“我只是不知道如何使它看起來…

讀取 wps_軟件前世今生篇之WPS(求伯君1988年先于OFFICE研發出WPS)

軟件前世今生篇之WPS今天給大家普及一下WPS這款辦公軟件&#xff0c;相信你會問wps有什么可普及的&#xff1f;我們都知道啊&#xff0c;不就是一款辦公軟件&#xff0c;而且還是抄襲office的&#xff0c;安裝還挺簡單的&#xff0c;而且還有一大堆廣告&#xff0c;不過使用免費…

吳恩達機器學習筆記11-梯度下降法實踐2-學習率

梯度下降算法收斂所需要的迭代次數根據模型的不同而不同&#xff0c;我們不能提前預知&#xff0c;我們可以繪制迭代次數和代價函數的圖表來觀測算法在何時趨于收斂。 也有一些自動測試是否收斂的方法&#xff0c;例如將代價函數的變化值與某個閥值&#xff08;例如0.001&#…