日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Web 現(xiàn)代應(yīng)用程序架構(gòu)下的性能優(yōu)化,漸進式的極致藝術(shù)

前言

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

創(chuàng)新互聯(lián)長期為超過千家客戶提供的網(wǎng)站建設(shè)服務(wù),團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為謝通門企業(yè)提供專業(yè)的網(wǎng)站建設(shè)、網(wǎng)站設(shè)計,謝通門網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。

  • 預(yù)渲染

  • 同構(gòu)渲染

  • 流式渲染

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

應(yīng)用架構(gòu)體系

當(dāng)我們討論「應(yīng)用架構(gòu)」的時候,可以理解為通過以下幾個部分組合來構(gòu)建網(wǎng)站。

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

性能指標(biāo)

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

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

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

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

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

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

如果你還不太熟悉這些指標(biāo)也沒關(guān)系,接下來的內(nèi)容中,會結(jié)合實際用例分析這些指標(biāo)。

渲染開銷 The cost of rendering

客戶端渲染 Client-side rendering

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

它的結(jié)構(gòu)一般如下:

分析一下它的流程:

  1. 用戶輸入網(wǎng)址進入網(wǎng)站,拉取 HTML 資源。

  1. HTML 資源中發(fā)現(xiàn) script 標(biāo)簽加載的 bundle 再一次發(fā)起請求拉取 bundle。此時也是性能統(tǒng)計指標(biāo)中的 FP 完成。

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

  1. JavaScript bundle 下載并執(zhí)行完畢,此時頁面才真正渲染出有意義的內(nèi)容。對應(yīng) FCP 完成。

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

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

服務(wù)端同構(gòu)渲染 SSR with Hydration

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

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

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

在同構(gòu)應(yīng)用中,只要 HTML 頁面返回,用戶就可以看到豐富多彩的頁面:

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

代碼對比

典型的 CSR React 應(yīng)用的代碼是這樣的:

而 SSR 的代碼則需要服務(wù)端的配合,

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

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

Vue 的 SSR 也是同理:

同構(gòu)的缺陷

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

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

因此,同構(gòu)應(yīng)用很可能變成一把「雙刃劍」。

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

Pre-rendering 預(yù)渲染。

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

當(dāng)然它也有很大的限制:

  1. 只適用于靜態(tài)頁面。

  2. 需要提前列舉出需要預(yù)渲染的 URLs。

流式渲染 Streaming

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

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

漸進式注水 Progressive Hydration

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

想象一下它的特點:

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

  2. 服務(wù)端依舊整頁渲染。

  3. 頁面可以根據(jù)優(yōu)先級來分片“啟動”組件。

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

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

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

首先來看看應(yīng)用的整體結(jié)構(gòu):

 
 
 
 
  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.      
  11.        
  12.        
  13.        
  14.     
 
  •   ); 
  • 根據(jù)客戶端和服務(wù)端的環(huán)境區(qū)分使用不同的 Hydrator ,在服務(wù)端就直接返回普通的 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.     
       
    8.        
    9.      
    10.   ); 

    而客戶端,則需要實現(xiàn)漸進式注水的關(guān)鍵部分:

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

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

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

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

     
     
     
     
    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(, this.root); 
    10.     }).observe(this.root); 
    11.   } 
    12.  
    13.   render() { 
    14.     return ( 
    15.       
    16.         ref={c => (this.root = c)} 
    17.         dangerouslySetInnerHTML={{ __html: '' }} 
    18.         suppressHydrationWarning 
    19.       /> 
    20.     ); 
    21.   } 

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

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

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

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

    當(dāng)然,我們了解原理就發(fā)現(xiàn),不光可以通過監(jiān)聽組件進入視圖來 hydrate ,甚至可以通過 hover 、 click 等時機來觸發(fā),根據(jù)業(yè)務(wù)需求的不同而靈活調(diào)整吧。

    可以訪問圖片中的網(wǎng)址獲取你喜歡的框架在這方面的相關(guān)文章:

    總結(jié)

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

    • 預(yù)渲染

    • 同構(gòu)渲染

    • 流式渲染

    • 漸進式注水

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

    完整 demo 地址:

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


    網(wǎng)頁題目:Web 現(xiàn)代應(yīng)用程序架構(gòu)下的性能優(yōu)化,漸進式的極致藝術(shù)
    文章路徑:http://www.5511xx.com/article/dhegehi.html