成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Web 現代應用程序架構下的性能優化,漸進式的極致藝術

新聞 前端
本文是谷歌工程師帶來的現代應用架構體系下的優化相關演講的總結,演講介紹了以下優化手段。

前言

本文是 Rendering on the Web: Performance Implications of Application Architecture (Google I/O ’19) [1] 這篇谷歌工程師帶來的現代應用架構體系下的優化相關演講的總結,演講介紹了以下優化手段:

  • 預渲染

  • 同構渲染

  • 流式渲染

  • 漸進式注水(非常精彩)

應用架構體系

當我們討論「應用架構」的時候,可以理解為通過以下幾個部分組合來構建網站。

  1. Component model 組件模型。
  2. Rendering and loading 渲染和加載。
  3. Routing and transitions 路由和過渡。
  4. Data/state management 數據、狀態的管理。

性能指標

在分析頁面渲染性能之前,先了解一下幾個比較重要的指標,方便下文理解:

  1. FP : First Paint,是 Paint Timing API 的一部分,是頁面導航與瀏覽器將該網頁的第一個像素渲染到屏幕上所用的中間時,渲染是任何與輸入網頁導航前的屏幕上的內容不同的內容。

  2. FCP : First Contentful Paint,首次有內容的渲染是當瀏覽器渲染 DOM 第一塊內容,第一次回饋用戶頁面正在載入。

  3. TTI : Time to interactive 第一次可交互時間,此時用戶可以真正的觸發 DOM 元素的事件,和頁面進行交互。

  4. FID : First Input Delay 第一輸入延遲測量用戶首次與您的站點交互時的時間(即,當他們單擊鏈接,點擊按鈕或使用自定義的 JavaScript 驅動控件時)到瀏覽器實際能夠的時間回應這種互動。

  5. TTFB : Time to First Byte 首字節時間,顧名思義,是指從客戶端開始和服務端交互到服務端開始向客戶端瀏覽器傳輸數據的時間(包括 DNS、socket 連接和請求響應時間),是能夠反映服務端響應速度的重要指標。

如果你還不太熟悉這些指標也沒關系,接下來的內容中,會結合實際用例分析這些指標。

渲染開銷 The cost of rendering

客戶端渲染 Client-side rendering

從服務端獲取 HTML、CSS、JavaScript 都是需要成本的,以一個 CSR(客戶端渲染)的網站為例,客戶端渲染的網站依賴框架庫(bundle)、應用程序(app)來進行初始化渲染,假設它有 1MB 的 JavaScript Bundle 代碼,那么只有當這一大段的代碼加載并執行完成以后,用戶才能看到頁面。

它的結構一般如下:

分析一下它的流程:

  1. 用戶輸入網址進入網站,拉取 HTML 資源。

  1. HTML 資源中發現 script 標簽加載的 bundle 再一次發起請求拉取 bundle。此時也是性能統計指標中的 FP 完成。

在這個階段,頁面基本上是沒什么意義的,當然你也可以放置一些靜態的骨架屏或者加載提示,來友好的提示用戶。

  1. JavaScript bundle 下載并執行完畢,此時頁面才真正渲染出有意義的內容。對應 FCP 完成。

當框架對 DOM 節點添加各類事件綁定后,用戶才真正可以和頁面交互,此時也對應 TTI 完成。

它的 缺點 在于,直到整個 JavaScript 依賴執行完成之前,用戶都看不到什么有意義的內容。

服務端同構渲染 SSR with Hydration

基于以上客戶端渲染的缺點以及用戶對于 CSR 應用交互更加豐富的需求,于是誕生了集 SSR 和 CSR 的 性能、SEO、數據獲取 的優點與一身的「 同構渲染 」,簡單點說,就是:

  1. 第一次請求,在服務端就利用框架提供的服務端渲染能力,直接原地請求數據,生成包含完整內容的 html 頁面,用戶不需要等待框架的 js 加載就可以看到內容。

  2. 等到頁面渲染后,再利用框架提供的 Hydration(注水)能力,讓服務端返回的“干癟”的 HTML 注冊事件等等,變的豐富起來,擁有了各種事件后,就和傳統 CSR 一樣擁有了豐富多彩的客戶端交互。

在同構應用中,只要 HTML 頁面返回,用戶就可以看到豐富多彩的頁面:

而 JavaScript 加載完畢后,用戶就可以和這些內容進行交互(比如點擊放大、跳轉頁面等等……)

代碼對比

典型的 CSR React 應用的代碼是這樣的:

而 SSR 的代碼則需要服務端的配合,

先由服務端通過 ReactDOMServer.renderToString 在服務端把組件給序列化成 html 字符串,返回給前端:

前端通過 hydrate 注水,使得功能交互變的完整:

Vue 的 SSR 也是同理:

同構的缺陷

至此看來,難道同構應用就是完美的嗎?當然不是,其實普通的同構應用只是提升了 FCP 也就是用戶看到內容的速度,但是卻還是要等到框架代碼下載完成, hydrate 注水完畢等一系列過程執行完畢以后才能真正的 可交互 。

并且對于 FID 也就是 First Input Delay 第一輸入延遲這個指標來說,由于 SSR 快速渲染出內容,更容易讓用戶誤以為頁面已經是可交互狀態,反而會使「用戶第一次點擊 - 瀏覽器響應事件」 這個時間變得更久。

因此,同構應用很可能變成一把「雙刃劍」。

下面我們來討論一些方案。

Pre-rendering 預渲染。

對于不經常發生變化的內容來說,使用預渲染是一種很好的辦法,它在代碼構建時就通過框架能力生成好靜態的 HTML 頁面,而不是像同構應用那樣在用戶請求頁面時再生成,這讓它可以幾乎立刻返回頁面。

當然它也有很大的限制:

  1. 只適用于靜態頁面。

  2. 需要提前列舉出需要預渲染的 URLs。

流式渲染 Streaming

流式渲染可以讓服務端對大塊的內容分片發送,使得客戶端不需要完整的接收到 HTML,而是接受到第一部分時就開始渲染,這大大提升了 TTFB 首字節時間。

在 React 中,可以通過 renderToNodeStream 來使用流式渲染:

漸進式注水 Progressive Hydration

我們知道 hydrate 的過程需要遍歷整顆 React 節點樹來添加事件,這在頁面很大的情況下耗費的時間一定是很長的,我們能否先只對關鍵的部分,比如視圖中可見的部分,進行「注水」,讓這部分先一步可以進行交互?

想象一下它的特點:

  1. 組件級別的漸進式注水。

  2. 服務端依舊整頁渲染。

  3. 頁面可以根據優先級來分片“啟動”組件。

通過一張動圖來直觀的感受一下普通注水(左)和漸進式注水(右)的區別:

可以看到用戶第一次可以交互的時間大大的提前了。

光說不做假把式,我們看看用 React 完成這個功能的代碼,首先我們需要準備一個組件 Hydrator 用來實現當某個組件 進入視圖范圍以后 再進行注水。

首先來看看應用的整體結構: 

  1. let load = () => import('./stream'); 
  2. let Hydrator = ClientHydrator; 
  3.  
  4. if (typeof window === 'undefined') { 
  5.   Hydrator = ServerHydrator; 
  6.   load = () => require('./stream'); 
  7.  
  8. export default function App() { 
  9.   return ( 
  10.     <div id="app"
  11.       <Header /> 
  12.       <Intro /> 
  13.       <Hydrator load={load} /> 
  14.     </div> 
  15.   ); 

根據客戶端和服務端的環境區分使用不同的 Hydrator ,在服務端就直接返回普通的 html 文本: 

  1. function interopDefault(mod) { 
  2.   return (mod && mod.default) || mod; 
  3.  
  4. export function ServerHydrator({ load, ...props }) { 
  5.   const Child = interopDefault(load()); 
  6.   return ( 
  7.     <section> 
  8.       <Child {...props} /> 
  9.     </section> 
  10.   ); 

而客戶端,則需要實現漸進式注水的關鍵部分:

  1. export class Hydrator extends React.Component { 
  2.   render() { 
  3.     return ( 
  4.       <section 
  5.         ref={c => (this.root = c)} 
  6.         dangerouslySetInnerHTML={{ __html: '' }} 
  7.         suppressHydrationWarning 
  8.       /> 
  9.     ); 
  10.   } 

首先 render 部分,利用 dangerouslySetInnerHTML 來使得這部分初始化為空的 html 文本,并且由于 server 端肯定還是和往常一樣全量渲染內容,而客戶端由于初始化需要先不做任何處理,會導致 React 內部對于服務端內容和客戶端內容的「一致性檢測」失敗。

而利用 dangerouslySetInnerHTML 的特性,會讓 React 不再進一步 hydrate 遍歷 children 而是直接沿用服務端渲染返回的 HTML,保證在注水前渲染的樣式也是 OK 的。

再利用 suppressHydrationWarning 取消 React 對于內容一致性檢測失敗的警告。

  1. export class Hydrator extends React.Component { 
  2.   componentDidMount() { 
  3.     new IntersectionObserver(async ([entry], obs) => { 
  4.       if (!entry.isIntersecting) return
  5.       obs.unobserve(this.root); 
  6.  
  7.       const { load, ...props } = this.props; 
  8.       const Child = interopDefault(await load()); 
  9.       ReactDOM.hydrate(<Child {...props} />, this.root); 
  10.     }).observe(this.root); 
  11.   } 
  12.  
  13.   render() { 
  14.     return ( 
  15.       <section 
  16.         ref={c => (this.root = c)} 
  17.         dangerouslySetInnerHTML={{ __html: '' }} 
  18.         suppressHydrationWarning 
  19.       /> 
  20.     ); 
  21.   } 

接下來,組件在客戶端初始化的時候,利用 IntersectionObserver 監控組件元素是否進入視圖,一旦進入視圖了,才會動態的去 import 組件,并且利用 ReactDOM.hydrate 來真正的進行注水。

此時不光注水是動態化的,包括組件代碼的下載都會在組件進入視圖時才發生,真正做到了「按需加載」。

動圖中紫色動畫出現,就說明漸進式 hydrate 完成了。

對比一下全量注水和漸進式注水的性能會發現首次可交互的時間被大大提前了:

當然,我們了解原理就發現,不光可以通過監聽組件進入視圖來 hydrate ,甚至可以通過 hover 、 click 等時機來觸發,根據業務需求的不同而靈活調整吧。

可以訪問圖片中的網址獲取你喜歡的框架在這方面的相關文章:

總結

本文通過總結了 Rendering on the Web: Performance Implications of Application Architecture (Google I/O ’19) [2] 這段 Google 團隊的精彩演講,來介紹了現代應用架構體系中的優化手段,包括:

  • 預渲染

  • 同構渲染

  • 流式渲染

  • 漸進式注水

在不同的業務場景下選擇對應的優化手段,是一名優秀的前端工程師必備的技能,相信看完這篇文章的你一定有所收獲。

完整 demo 地址:

https://github.com/GoogleChromeLabs/progressive-rendering-frameworks-samples

 

 

責任編輯:張燕妮 來源: 前端從進階到入院
相關推薦

2024-11-04 16:04:06

2014-12-16 13:51:55

華為eSpace UC統一通信

2019-10-17 10:10:23

優化Web前端

2021-07-22 09:00:00

SPAPWAWeb

2023-09-28 07:34:33

2010-11-15 16:20:33

Oracle系統優化

2010-04-27 13:41:42

云計算

2017-11-20 17:40:52

谷歌web程序員

2021-07-16 06:40:19

Argo RollouAnalysis云原生

2022-05-09 17:33:23

PWA漸進式Web應用程序離線優先

2010-07-22 08:54:14

jQuery

2015-02-02 15:46:59

Web應用架構大數據

2023-03-30 08:29:14

HTTP緩存Web應用

2021-01-13 13:49:29

漸進式網頁應用應用程序開發

2011-09-20 10:41:45

Web

2023-01-09 17:04:24

2022-08-22 10:40:40

Kubernete部署分析運行

2023-04-11 07:59:56

Kruise漸進式交付

2009-07-09 16:47:26

Servlet的Web

2009-04-01 14:33:33

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩中出 | 国产成人精品一区二区三区在线 | 91福利影院 | www.一区二区三区 | 天天插天天狠天天透 | 色久影院 | 亚洲欧美日韩网站 | 国产成人在线视频 | 一区二区三区国产精品 | 亚洲一区二区综合 | 亚洲成人免费av | 国内久久 | 久久久久免费 | 色婷婷综合久久久中字幕精品久久 | chinese中国真实乱对白 | 亚洲免费视频网址 | 欧美精品一区二区三区四区五区 | 一级黄色片一级黄色片 | 欧美日韩一卡 | 久久偷人 | 伊人热久久 | 精品视频在线免费观看 | 欧美亚洲一区二区三区 | 国产xxxx在线 | 亚洲协和影视 | 91伊人网 | 伊人一区 | 久久精品色欧美aⅴ一区二区 | 亚洲毛片在线观看 | 国产一区二区三区在线看 | 亚洲一区二区三区在线播放 | 国产精品视频一二三区 | 久久精品一区 | 日本黄色影片在线观看 | 欧美在线a| 成人在线视频免费观看 | 亚洲精品视频一区 | 一区精品视频在线观看 | 亚洲欧洲成人 | 国产精品一区在线 | 亚洲视频一区在线播放 |