1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        現(xiàn)代前端框架的渲染模式

        共 8964字,需瀏覽 18分鐘

         ·

        2023-06-12 04:26

        React 發(fā)布已經(jīng)十年了,筆者接觸前端差不多也有十年時(shí)間了。說實(shí)話,如果沒有 Head First 系列圖書,我可能都沒有走上編程這條道路。

        acdaae6b7c86ac11a96fedab174e2643.webpHead first


        盡管現(xiàn)在看來這系列圖書內(nèi)容可能過時(shí)了。

        Head First 系列圖書讓我知道,原來編程也可以這么通俗易懂的,對(duì)于剛接觸這個(gè)領(lǐng)域的同學(xué)來說,從這里可以獲得很多信心和成就感。這種風(fēng)格也一直影響著我,學(xué)習(xí)和工作、傳道授業(yè)過程中,我會(huì)努力把復(fù)雜的事情簡化、通俗化,提煉本質(zhì)。


        這十年,前端渲染方式一直在演進(jìn),我覺得大概可以分為以下三個(gè)階段:

        7434f179c529833ca4680b826268c016.webpUntitled
        • 傳統(tǒng) SSR: 那時(shí)候前端還沒有分離,在 JSP、ASP、Ruby on Rails、Django 這些 MVC 框架下,通過模板來渲染頁面。jQuery 是這個(gè)階段的主角
        • 前后端分離:從 Node.js 發(fā)布,到目前為止,是前端發(fā)展最迅速的 10 年。前后端分離的典型代表是 Angular 和 React、Vue 等框架,我覺得,促進(jìn)前后端分離的主要原因還是隨著需求的復(fù)雜化,分工精細(xì)化了。前端可以專注于 UI 的設(shè)計(jì)和交互邏輯。后端只需要提供 API,不需要關(guān)心前端的具體實(shí)現(xiàn)。
        • 同構(gòu)前端:這幾年前端框架的發(fā)展進(jìn)入的深水區(qū),隨著云原生、容器技術(shù)、Serverless、邊緣計(jì)算等底層技術(shù)設(shè)施的普及,也讓‘前端’生存范圍延展到服務(wù)端。前端開始尋求 UXDX 的平衡點(diǎn)

        通過這篇文章,你就可以知道近些年前端渲染模式的演變。廢話不多說,直接開始吧。


        CSR - 客戶端渲染

        6f8e97edebd6f4c610af0dfc82e03c74.webpUntitled

        這個(gè)我們?cè)偈煜げ贿^了, 即前端頁面在瀏覽器中渲染,服務(wù)端僅僅是靜態(tài)資源服務(wù)器(比如 nginx)。

        初始的 HTML 文件只是一個(gè)空殼,我們需要等待 JavaScript 包加載和執(zhí)行完畢,才能進(jìn)行交互,白屏?xí)r間比較長。

        • 優(yōu)點(diǎn)
          • 部署簡單
          • 頁面過渡、功能交互友好
          • 適合復(fù)雜交互型應(yīng)用程序開發(fā)
        • 缺點(diǎn)
          • SEO 不友好
          • 白屏?xí)r間長
          • 可能需要復(fù)雜的狀態(tài)管理。時(shí)至今日,狀態(tài)管理方面的輪子還在不停地造

        a1639225bd6761e72378c49a22b2c11f.webp


        SSR - 服務(wù)端渲染

        0cf82c5f5a0444dd0187282f6249e956.webpUntitled

        為了解決 SEO 和白屏問題,各大框架開始支持在服務(wù)端渲染 HTML 字符串。

        SSR 把數(shù)據(jù)拉取放到了服務(wù)端,因?yàn)殡x數(shù)據(jù)源比較近,數(shù)據(jù)拉取的速度會(huì)快一點(diǎn)。但這也不是完全沒有副作用,因?yàn)樾枰诜?wù)端等待數(shù)據(jù)就緒, TTFB(Time to First Byte) 相比 CSR 會(huì)長一點(diǎn)。

        SSR 只是給我們準(zhǔn)備好了初始的數(shù)據(jù)和 HTML, 實(shí)際上和 CSR 一樣,我們還是需要加載完整的客戶端程序,然后在瀏覽器端重新渲染一遍(更專業(yè)的說是 Hydration 水合/注水),才能讓 DOM 有交互能力。

        也就說, FCP(First Contentful Paint) 相比 CSR 提前了, 但是 TTI(Time to Interactive) 并沒有太多差別。只是用戶可以更快地看到內(nèi)容了。

        hydration 的主要目的是掛載事件處理器、觸發(fā)副作用等等

        優(yōu)點(diǎn)

        • SEO 友好
        • 用戶可以更快看到內(nèi)容了

        缺點(diǎn)

        • 部署環(huán)境要求。需要 Nodejs 等 JavaScript 服務(wù)端運(yùn)行環(huán)境
        • 需要包含完整的 JavaScript 客戶端渲染程序,TTI 還有改善空間




        SSG - 靜態(tài)生成

        5c5832b694717b75a822eed18051c614.webpUntitled

        對(duì)于完全靜態(tài)的頁面,比如博客,公司主頁等等,也可以使用 SSG 靜態(tài)渲染。

        和 SSR 的區(qū)別是,SSG 是在構(gòu)建時(shí)渲染的。

        和 CSR 一樣,因?yàn)槭庆o態(tài)的,所以在服務(wù)端不需要渲染運(yùn)行時(shí),部署在靜態(tài)服務(wù)器就行了。

        VuePress、VitePress、Gatsby、Docusaurus 這些框架都屬于 SSG 的范疇。



        優(yōu)點(diǎn)

        • 相比 SSR, 因?yàn)椴恍枰?wù)端運(yùn)行時(shí)、數(shù)據(jù)拉取,TTFB/FCP 等都會(huì)提前。

        缺點(diǎn)

        • 和 SSR 一樣,也有客戶端渲染程序、需要進(jìn)行 Hydrate。對(duì)于內(nèi)容為中心的站點(diǎn)來說,實(shí)際上并不需要太多交互,客戶端程序還有較大壓縮的空間。
        • 在構(gòu)建時(shí)渲染,如果內(nèi)容變更,需要重新構(gòu)建,比較麻煩




        ISG - 增量靜態(tài)生成

        e93e0723c9f3fe93b5c3521c695b48aa.webpUntitled

        ISG 是 SSG 的升級(jí)版。解決 SSG 內(nèi)容變更繁瑣問題。

        ISG 依舊會(huì)在構(gòu)建時(shí)預(yù)渲染頁面,但是這里多出了一個(gè)服務(wù)端運(yùn)行時(shí),這個(gè)運(yùn)行時(shí)會(huì)按照一定的過期/刷新策略(通常會(huì)使用 stale-while-revalidate )來重新生成頁面。



        Progressive Hydration - 漸進(jìn)水合

        c9c0f5f22420b6d398666a37f1cb3aff.webpUntitled

        上文提到,常規(guī)的 SSR 通常需要完整加載客戶端程序(上圖的 bundle.js),水合之后才能得到可交互頁面,這就導(dǎo)致 TTI 會(huì)偏晚。

        最直接的解決辦法就是壓縮客戶端程序的體積。那么自然會(huì)想到使用代碼分割(code splitting)技術(shù)。漸進(jìn)式水合 (Progressive Hydration ) 就是這么來的。

        如上圖,我們使用代碼分割的方式,將 Foo、Bar 抽取為異步組件,抽取后主包的體積下降了,TTI 就可以提前了。

        而 Foo、Bar 可以按照一定的策略來按需加載和水合,比如在視口可見時(shí)、瀏覽器空閑時(shí),或者交給 React Concurrent Mode 根據(jù)交互的優(yōu)先級(jí)來加載。

        React 18 官方支持了漸進(jìn)式水合(官方叫 Selective Hydration)。

        要深入了解 Progress Hydration, 可以看這個(gè)視頻。


        SSR with streaming - 流式 SSR

        00a4516898a410086582d3a424bf7650.webpUntitled

        這個(gè)很好理解。尤其是在最近 ChatGPT 這么火。ChatGPT API 有兩種響應(yīng)模式:普通響應(yīng)、流式響應(yīng)

        • renderToString → 普通響應(yīng)。即 SSR 會(huì)等待完整的 HTML 渲染完畢后,才給客戶端發(fā)送第一個(gè)字節(jié)。
        • renderToNodeStream → 流式響應(yīng)。渲染多少,就發(fā)送多少。就像 ChatGPT 聊天消息一樣,一個(gè)字一個(gè)字的蹦,盡管接收完整消息的時(shí)間可能差不多,用戶體驗(yàn)卻相差甚遠(yuǎn)。

        瀏覽器能夠很好地處理 HTML 流,快速地將內(nèi)容呈現(xiàn)給用戶,而不是白屏干等。

        下面這張圖可以更直觀感受兩者區(qū)別:

        6b53fe2a6069a84f23d705243bde94ca.webp來源:https://mxstbr.com/thoughts/streaming-ssr/

        來源:https://mxstbr.com/thoughts/streaming-ssr/

        對(duì)于常規(guī)的流式 SSR,優(yōu)化效果可能沒有我們想象的那么明顯。因?yàn)榭蚣苓€是得等數(shù)據(jù)拉取完成之后才能開始渲染。因此,除非是比較復(fù)雜、長序列的 HTML 樹,至上而下需要較長時(shí)間的渲染,否則效果并不明顯。

        優(yōu)點(diǎn)

        • 相比普通響應(yīng),流式響應(yīng)可以提前 TTFB 和 FCP, 瀏覽器不用空轉(zhuǎn)等待,可以連續(xù)繪制。

        缺點(diǎn)

        • 數(shù)據(jù)拉取是 TTFB/FCP 的主要阻塞原因。為了解決這個(gè)問題,下文的 Selective Hydration 如何巧妙地解決這個(gè)問題。

        Selective Hydration - 選擇性水合

        93a836ecfa3b4d7ccd244a6d96094833.webpUntitled

        選擇性水合(Progressive Hydration)漸進(jìn)式水合(Progressive Hydration)流式SSR(SSR with Streaming) 的升級(jí)版。主要通過選擇性地跳過‘慢組件’,避免阻塞,來實(shí)現(xiàn)更快的 HTML 輸出, 從而讓流式響應(yīng)發(fā)揮應(yīng)有的作用。

        慢組件通常指的是:需要異步獲取數(shù)據(jù)、體積較大、或者是計(jì)算量比較復(fù)雜的組件。

        比較典型的慢組件是異步數(shù)據(jù)獲取的組件, 如下圖,未開啟 Selective Hydration 的情況,會(huì)等待所有異步任務(wù)完成后才開始輸出,而 Selective Hydration 可以跳過這些組件,等待它們就緒后,繼續(xù)輸出。

        ab28ffdd920477b857269764a7407e80.webpUntitled

        我們可以在最新的 Next.js(當(dāng)前是 13.4) 演示一下。

        沒有開啟 Selective Hydration 的 Demo:
              
              function delay(time: number) {
        return new Promise((resolve) => setTimeout(resolve, time))
        }

        /**
        * 獲取關(guān)鍵數(shù)據(jù)
        */
        function getCrucialData() {
        return delay(1000).then(() => {
        return {
        data: Math.random(),
        }
        })
        }

        function getData(time: number) {
        return delay(time).then(() => {
        return {
        data: Math.random(),
        }
        })
        }

        const Foo = async () => {
        const data = await getData(1000)

        return
        foo: {data.data}

        }

        const Bar = async () => {
        const data = await getData(2000)

        return
        bar: {data.data}

        }

        /**
        * 頁面 ??
        *
        */
        export default async function WithoutSelective() {
        // 獲取關(guān)鍵數(shù)據(jù)
        const crucialData = await getCrucialData()

        return (

        Without Selective


        This page is rendered without Selective Hydration.


        crucial data: {crucialData.data}





        )
        }

        運(yùn)行結(jié)果:瀏覽器等待響應(yīng)的時(shí)間為 3s3202bb1292096d1d9605d8ec661f1b1e.webp即所有服務(wù)端組件(Server Component) 就緒后才會(huì)有實(shí)際的內(nèi)容輸出。



        開啟 Selective Hydration 很簡單,我們只需要用 Suspend 包裹起來,提示 React 這可能是一個(gè)‘慢組件’,可以跳過他:

              
              export default async function WithoutSelective() {
        // 獲取關(guān)鍵數(shù)據(jù)
        const crucialData = await getCrucialData()

        return (

        Without Selective


        This page is rendered without Selective Hydration.


        crucial data: {crucialData.data}









        )
        }

        現(xiàn)在來看運(yùn)行結(jié)果:

        0864a29fcd97f661056842fe3f490985.webpUntitled

        明顯 TTFB 提前了!但是完整的請(qǐng)求時(shí)間沒變。


        當(dāng) Foo 和 Bar 就緒后,Next.js 會(huì)將渲染結(jié)果寫入流中。怎么做到的?


        看一眼 HTML 就知道了:

        2b47c27334d1f54a01013c212e201ac8.webpUntitled

        對(duì)于慢組件,React 會(huì)先渲染 Suspend 的 fallback 內(nèi)容,并留一個(gè)插槽。

        繼續(xù)往下看,可以看到 Foo、Bar 的渲染結(jié)果:

        050d03b3a7433b3ba76f593d82978d44.webpUntitled

        接著將渲染結(jié)果替換掉插槽。用于后續(xù)的水合。




        總之,在服務(wù)端,Selective Hydration 在 SSR With Streaming 的基礎(chǔ)上,通過選擇性地跳過一些低優(yōu)先級(jí)的慢組件來優(yōu)化了 TTFB(主要的,相對(duì)于 FCP 等指標(biāo)也優(yōu)化了),更快地向用戶呈現(xiàn)頁面。

        在客戶端 Selective Hydration 的運(yùn)行過程同 Progressive Hydration 。

        關(guān)于 Selective Hydration 細(xì)節(jié),可以閱讀以下文章:

        • New in 18: Selective Hydration
        • New Suspense SSR Architecture in React 18

        Islands Architecture - 島嶼架構(gòu)

        6b6d6e46b5c431b248d012af6516ff51.webpUntitled

        近兩年,去 JavaScript 成為一波小趨勢(shì),這其中的典型代表是 Islands Architecture (島嶼架構(gòu))和 React Server Component(RSC, React 服務(wù)端組件)。

        它們主張是:在服務(wù)端渲染,然后去掉不必要 JavaScript

        島嶼架構(gòu)的主要代表是 Astro。如上圖,Astro 在服務(wù)端渲染后,默認(rèn)情況下,在客戶端側(cè)沒有客戶端程序和水合的過程。而對(duì)于需要 JavaScript 增強(qiáng),實(shí)現(xiàn)動(dòng)態(tài)交互的組件,需要顯式標(biāo)記為島嶼。


        這有點(diǎn)類似 Progressive Hydration 的意思。但是還是有很大的差別:

        • 島嶼是在去 JavaScript 這個(gè)背景下的交互增強(qiáng)手段。按 Astro 解釋是:你可以將‘島嶼’想象成在一片由靜態(tài)(不可交互)的 HTML 頁面中的動(dòng)態(tài)島嶼
        • 每個(gè)島嶼都是獨(dú)立加載、局部水合。而 Progressive Hydration 是整棵樹水合的分支,只不過延后了。
        • 島嶼可以框架無關(guān)。

        去 JavaScript 后,可以緩解典型的 SSR TTI 問題。但是島嶼架構(gòu)并不能通吃所有的場景,最擅長的是”內(nèi)容為中心“的站點(diǎn),即當(dāng)靜態(tài)的頁面比重遠(yuǎn)高于動(dòng)態(tài)比重時(shí),去 JavaScript 的收益才是顯著的。




        React Server Component - React 服務(wù)端組件

        d10484a756c4ee6b6d81d33729ba7243.webpUntitled

        在筆者看來,React Server Component(RSC) 本質(zhì)上和島嶼架構(gòu)的目的是一樣的,都是去 JavaScript。只是實(shí)現(xiàn)的手段不同。


        這是 Next.js 官方文檔的示例圖:和島嶼架構(gòu)類似,對(duì)于靜態(tài)的內(nèi)容推薦使用 Server Component (SC), 而需要交互增強(qiáng)的,可以使用 Client Component (CC)。

        25563bfa30c112edab7906cbba4de05e.webpUntitled

        顧名思義,RSC 就是只能在服務(wù)端運(yùn)行的組件。下面簡單對(duì)比一下兩者的區(qū)別:


        Server Component Client Component
        運(yùn)行環(huán)境 服務(wù)端 - 服務(wù)端 + 客戶端
        - 僅客戶端

        JavaScript 服務(wù)端組件依賴的相關(guān)程序?qū)蛻舳瞬豢梢姟?/td>
        在這里實(shí)現(xiàn)了 ‘去 JavaScript’ 需要打包分發(fā)給客戶端
        水合 不需要水合 需要水合
        支持 async Y N
        支持狀態(tài)(state, context) N Y
        支持事件、副作用 N Y

        RSC 優(yōu)點(diǎn)類似 React Hooks 出來之前的函數(shù)組件: 就是一個(gè)普通的函數(shù),不能使用 hooks,沒有狀態(tài),只會(huì)被調(diào)用一次。

        你可以通過 Next.js 的文檔,深入學(xué)習(xí) RSC。React 官方的討論組也是不錯(cuò)的一手學(xué)習(xí)場地。



        那么相比島嶼架構(gòu)呢?

        優(yōu)點(diǎn)

        • Server Component 和 Client Component 都是 React 框架的組件,盡管有些區(qū)別,但是心智模型是統(tǒng)一的。
        • React Server Component 是 React 框架下一體化的原生解決方案,支持和 Selective Hydration 配合使用。島嶼架構(gòu)只是一個(gè)架構(gòu)模式。
        • 可以進(jìn)行更細(xì)粒度和更靈活的組合。

        缺點(diǎn)

        • Server Component 和 Client Component 還是有較大差別,在組合、通信上也有較多限制,需要開發(fā)者規(guī)劃好服務(wù)端和客戶端的邊界。初期有一定上手門檻。當(dāng)然,Islands 可能也有類似的問題。



        總結(jié)

        本文篇幅較長,我給大家整理了這些渲染模式的發(fā)展歷程和關(guān)系脈絡(luò)

        8f5e0843b05d8f4ee7421ebd51132c17.webpUntitled

        任何技術(shù)的迭代都是有其動(dòng)機(jī)和脈絡(luò)。不推薦大家面向熱度編程,大部分情況下,做到‘知其然,也知其所以然’,就足夠了。




        擴(kuò)展閱讀

        本文主要參考的內(nèi)容來源是patterns.dev。這個(gè)網(wǎng)站收錄了許多實(shí)用的前端設(shè)計(jì)模式,大家趕緊收藏起來!


        • Pattern dev
        • Next.js
        • Next.js Incremental Static RegenerationExamples
        • reactwg/server-components
        • Is 0kb of JavaScript in your Future?
        • Islands Architecture

        以上便是本次分享的全部內(nèi)容,希望對(duì)你有所幫助^_^

        喜歡的話別忘了 分享、點(diǎn)贊、收藏 三連哦~。

        6da444aed1ee7c65fef6d7d05178a726.webp

        從零搭建全??梢暬笃林谱髌脚_(tái)V6.Dooring

        從零設(shè)計(jì)可視化大屏搭建引擎

        Dooring可視化搭建平臺(tái)數(shù)據(jù)源設(shè)計(jì)剖析

        可視化搭建的一些思考和實(shí)踐

        基于Koa + React + TS從零開發(fā)全棧文檔編輯器(進(jìn)階實(shí)戰(zhàn)




        點(diǎn)個(gè)在看你最好看

        瀏覽 127
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            波多野结衣三级在线观看 | 人人鲁人人爱 | 小骚逼操逼 | 日本免费在线黄色视频 | www,操逼| 欧美午夜福利在线 | 国产精品网红系列 | 成人免费黄色小说 | 人人摸人人射 | 国精产品一区一区三区mba下载 |