<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何在 React 18中 利用Suspense 實(shí)現(xiàn) 服務(wù)端渲染(SSR)

          共 8673字,需瀏覽 18分鐘

           ·

          2022-03-04 21:09

          概述


          React 18 將包括對(duì) 其服務(wù)器端渲染 (SSR) 性能的架構(gòu)做了改進(jìn)。這些改進(jìn)帶來(lái)了實(shí)質(zhì)性的效果,是幾年來(lái)其團(tuán)隊(duì)工作的結(jié)晶。大多數(shù)的改進(jìn)點(diǎn)都是在幕后進(jìn)行的,但您需要了解一些選擇加入機(jī)制,尤其是您在不適用框架的情況下。
          主要的新API是 pipeToNoWritable, 您可以在 "升級(jí)到服務(wù)器上的React18" 這篇文章中閱讀了解。在最終的正式版本中,我們也將計(jì)劃寫更多關(guān)于它的細(xì)節(jié)。

          如何在服務(wù)端使用React18

          https://github.com/reactwg/react-18/discussions/22
          現(xiàn)有的API是 ,此文主要是對(duì)新架構(gòu)、其設(shè)計(jì)及背后要解決的問(wèn)題進(jìn)行闡述。

          服務(wù)端渲染(SSR)介紹


          服務(wù)器端渲染(在本文中縮寫為“SSR”)讓您可以從服務(wù)器上的 React 組件生成 HTML,并將該 HTML 發(fā)送給您的用戶。SSR 允許您的用戶在您的 JavaScript 包加載和運(yùn)行之前查看頁(yè)面的內(nèi)容。

          React 中的 SSR 總是發(fā)生在幾個(gè)步驟中:

          • 在服務(wù)器端,獲取整個(gè)應(yīng)用程序的數(shù)據(jù)。

          • 在服務(wù)器端,將整個(gè)應(yīng)用程序呈現(xiàn)為 HTML 字符串并將其發(fā)送到客戶端。

          • 在客戶端,加載整個(gè)應(yīng)用程序的JavaScript 代碼。

          • 在客戶端,將JavaScript 邏輯連接到整個(gè)應(yīng)用程序的服務(wù)器生成的HTML(這就是“hydration”)。

          關(guān)鍵部分是,在下一步開始之前,整個(gè)應(yīng)用程序的每個(gè)步驟都必須立即完成。如果其中一個(gè)環(huán)節(jié)比其他部分慢,將會(huì)影響整體的加載時(shí)間。

          React18中,您可以使用? 將您的應(yīng)用程序分解成更小的獨(dú)立單元,每個(gè)模塊都是獨(dú)自異步加載,并不會(huì)影響其余部分。即便是應(yīng)用程序中最慢的模塊也不會(huì)拖累較快的模塊。因此,用戶也將更快地看到內(nèi)容,并更快的開始與之交互。

          這些改進(jìn)點(diǎn)都是框架內(nèi)部自動(dòng)完成的,您無(wú)需為它們編寫任何特殊的代碼。

          通過(guò)案例演示來(lái)介紹什么是SSR ?


          當(dāng)用戶加載您的應(yīng)用程序時(shí),您希望更快顯示一個(gè)完全交互式的頁(yè)面:

          此插圖使用綠色表示頁(yè)面的這些部分是交互式的。換句話說(shuō),它們所有的 JavaScript 事件處理程序都已附加,單擊按鈕可以更新?tīng)顟B(tài),等等。

          但是,頁(yè)面在 JavaScript 代碼完全加載之前無(wú)法進(jìn)行交互。這包括 React 本身和您的應(yīng)用程序代碼。對(duì)于非React的應(yīng)用程序,大部分加載時(shí)間將用于下載您的應(yīng)用程序代碼。

          如果您不使用 SSR,則用戶在 JavaScript 加載時(shí)只會(huì)看到一個(gè)空白頁(yè)面:

          出現(xiàn)空白頁(yè)面對(duì)用戶來(lái)說(shuō)非常的不友好,這也是我們推薦使用 SSR的原因。SSR允許您將服務(wù)器上的React組件渲染為HTML字符串并將其發(fā)送給用戶。HTML的交互性不是很強(qiáng)(除了簡(jiǎn)單內(nèi)置Web交互,如鏈接和表單輸入)。然而,它讓用戶在JavaScript仍在加載時(shí)可以看到一些內(nèi)容:

          以上圖例中,灰色說(shuō)明屏幕的這些部分尚未完全交互。您應(yīng)用程序的JavaScript代碼尚未加載,因此單機(jī)按鈕不會(huì)執(zhí)行任何操作。但特別是對(duì)于內(nèi)容較多的站點(diǎn),SSR 非常有用,因?yàn)樗梢宰屵B接較差的用戶在JavaScript加載時(shí)開始閱讀或查看內(nèi)容。

          當(dāng) React 和你的應(yīng)用程序代碼都加載時(shí),你想讓這個(gè) HTML 交互。你告訴 React:“這是App在服務(wù)器上生成這個(gè) HTML的組件。將事件處理程序附加到該 HTML!” React 將在內(nèi)存中渲染你的組件樹,但它不會(huì)為它生成 DOM 節(jié)點(diǎn),而是將所有邏輯附加到現(xiàn)有的 HTML。

          渲染組件和附加事件處理程序的過(guò)程稱為“水化”。這就像用交互性和事件處理程序的“水”去澆灌“干涸”的 HTML。(或者至少,這就是我對(duì)自己解釋這個(gè)術(shù)語(yǔ)的方式。)

          水合之后,它是“像往常一樣反應(yīng)”:你的組件可以設(shè)置狀態(tài),響應(yīng)點(diǎn)擊等等:

          你可以看到 SSR 是一種“魔術(shù)”。它不會(huì)使您的應(yīng)用程序完全交互更快。相反,它可以讓您更快地顯示應(yīng)用程序的非交互式版本,以便用戶可以在等待 JS 加載時(shí)查看靜態(tài)內(nèi)容。然而,這個(gè)技巧對(duì)網(wǎng)絡(luò)連接不佳的人產(chǎn)生了巨大的影響,并提高了整體感知性能。由于其更容易的索引和更快的速度,它還可以幫助您進(jìn)行搜索引擎排名。


          注意:不要將 SSR 與服務(wù)器組件混淆。服務(wù)器組件是一個(gè)更具實(shí)驗(yàn)性的功能,仍在研究中,可能不會(huì)成為最初的 React 18 版本的一部分。您可以復(fù)制以下連接了解服務(wù)器組件。服務(wù)器組件是對(duì) SSR 的補(bǔ)充,并將成為推薦的數(shù)據(jù)獲取方法的一部分,但本文與它們無(wú)關(guān)。

          React服務(wù)器組件

          https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html


          現(xiàn)有 SSR 存在哪些問(wèn)題?


          上述方法有效,但在很多方面表現(xiàn)不佳。

          1. 您必須獲取所有內(nèi)容,然后才能顯示任何內(nèi)容【整個(gè)過(guò)程是 同步進(jìn)行的】

          今天 SSR 的一個(gè)問(wèn)題是它不允許組件“等待數(shù)據(jù)”。使用當(dāng)前的 API,當(dāng)您呈現(xiàn)為 HTML 時(shí),您必須為服務(wù)器上的組件準(zhǔn)備好所有數(shù)據(jù)。這意味著您必須先收集服務(wù)器上的所有數(shù)據(jù),然后才能開始向客戶端發(fā)送任何HTML。這是相當(dāng)?shù)托У摹?/span>


          例如,假設(shè)您要呈現(xiàn)帶有評(píng)論的帖子。盡早顯示注釋很重要,因此您希望將它們包含在服務(wù)器 HTML 輸出中。但是您的數(shù)據(jù)庫(kù)或 API 層很慢,這是您無(wú)法控制的。現(xiàn)在你必須做出一些艱難的選擇。如果您將它們從服務(wù)器輸出中排除,則在 JS 加載之前用戶將不會(huì)看到它們。但是,如果您將它們包含在服務(wù)器輸出中,則必須延遲發(fā)送其余的 HTML(例如,導(dǎo)航欄、側(cè)邊欄,甚至是帖子內(nèi)容),直到評(píng)論加載完畢并且您可以呈現(xiàn)完整的樹。這不是很友好。

          作為旁注,一些數(shù)據(jù)獲取解決方案反復(fù)嘗試將樹渲染為 HTML 并丟棄結(jié)果,直到數(shù)據(jù)得到解析,因?yàn)?React 沒(méi)有提供更符合人體工程學(xué)的選項(xiàng)。我們希望提供一種不需要如此極端妥協(xié)的解決方案。

          2. 給任何板塊補(bǔ)水之前,您必須加載所有數(shù)據(jù)

          在您的 JavaScript 代碼加載后,您將告訴 React “水合” HTML 并使其具有交互性。React 將在渲染組件時(shí)“遍歷”服務(wù)器生成的 HTML,并將事件處理程序附加到該 HTML。為此,瀏覽器中組件生成的樹必須與服務(wù)器生成的樹相匹配。否則 React 無(wú)法“匹配它們!” 這樣做的一個(gè)非常不幸的后果是,您必須先為客戶端上的所有組件加載 JavaScript,然后才能開始對(duì)它們中的任何一個(gè)進(jìn)行補(bǔ)水。


          例如,假設(shè)評(píng)論小部件包含很多復(fù)雜的交互邏輯,為其加載 JavaScript 需要一段時(shí)間。現(xiàn)在你必須再次做出艱難的選擇。最好將服務(wù)器上的評(píng)論呈現(xiàn)為 HTML,以便盡早將它們顯示給用戶。但是因?yàn)榻裉熘荒芤淮瓮瓿裳a(bǔ)水,所以在您加載評(píng)論小部件的代碼之前,您無(wú)法開始對(duì)導(dǎo)航欄、側(cè)邊欄和帖子內(nèi)容進(jìn)行補(bǔ)水!當(dāng)然,您可以使用代碼拆分并單獨(dú)加載它,但是您必須從服務(wù)器 HTML 中排除注釋。否則 React 將不知道如何處理這塊 HTML(它的代碼在哪里?)并在水化過(guò)程中將其刪除。

          3. 在與任何事物交互之前,您必須先補(bǔ)充所有水分

          融合作用本身也存在類似的問(wèn)題。今天,React 一次性完成樹的水化。這意味著一旦它開始 hydrating(本質(zhì)上是調(diào)用你的組件函數(shù)),React 不會(huì)停止,直到它為整個(gè)樹完成此操作。因此,您必須等待所有組件都 “融合” 后才能與它們中的任何一個(gè)進(jìn)行交互。


          例如,假設(shè)評(píng)論小部件具有昂貴的渲染邏輯。它可能在您的計(jì)算機(jī)上運(yùn)行得很快,但在運(yùn)行所有這些邏輯的低端設(shè)備上并不便宜,甚至可能會(huì)鎖定屏幕幾秒鐘。當(dāng)然,理想情況下,我們根本不會(huì)在客戶端上有這樣的邏輯(服務(wù)器組件可以提供幫助)。但是對(duì)于某些邏輯來(lái)說(shuō),這是不可避免的,因?yàn)樗鼪Q定了附加的事件處理程序應(yīng)該做什么并且對(duì)于交互性至關(guān)重要。因此,一旦水化開始,用戶就無(wú)法與導(dǎo)航欄、側(cè)邊欄或帖子內(nèi)容進(jìn)行交互,直到整個(gè)樹被水化。對(duì)于導(dǎo)航,這尤其令人遺憾,因?yàn)橛脩艨赡芟M耆x開此頁(yè)面——但由于我們正忙于補(bǔ)充水分,我們將它們保留在他們不再關(guān)心的當(dāng)前頁(yè)面上。


          我們?nèi)绾谓鉀Q這些問(wèn)題呢 ?


          這些問(wèn)題之間有一個(gè)共同點(diǎn)。它們迫使你在早點(diǎn)做某事(但因?yàn)樗柚顾衅渌ぷ鞫鴵p害用戶體驗(yàn))或晚做某事(但因?yàn)槟憷速M(fèi)時(shí)間而損害用戶體驗(yàn))之間做出選擇。

          這是因?yàn)橛幸粋€(gè)過(guò)程:獲取數(shù)據(jù)(服務(wù)器)→ 渲染到 HTML(服務(wù)器)→ 加載代碼(客戶端)→ 水合物(客戶端)。在應(yīng)用程序的前一階段完成之前,這兩個(gè)階段都不能開始。這就是它效率低下的原因。我們的解決方案是將工作分開,以便我們可以為屏幕的一部分而不是整個(gè)應(yīng)用程序執(zhí)行每個(gè)階段。

          這不是一個(gè)新穎的想法:例如,

          Marko[https://tech.ebayinc.com/engineering/async-fragments-rediscovering-progressive-html-rendering-with-marko/]?是實(shí)現(xiàn)此模式版本的 JavaScript Web 框架之一。挑戰(zhàn)在于如何使這樣的模式適應(yīng) React 編程模型。花了一段時(shí)間才解決。我們在 2018 年為此目的引入了該組件。我們引入它時(shí)僅支持在客戶端延遲加載代碼。但目標(biāo)是將其與服務(wù)器渲染集成并解決這些問(wèn)題。


          讓我們看看如何在 React 18 中使用來(lái)解決這些問(wèn)題。


          React 18 :流式 HTML 和 選擇性的?“水化”


          Suspense 解鎖的 React 18 中有兩個(gè)主要的 SSR 特性:

          • 在服務(wù)器上流式傳輸 HTML。要選擇使用它,您需要renderToString從新pipeToNodeWritable方法切換到新方法,如此處所述

          • 對(duì)客戶進(jìn)行選擇性水合作用。要選擇加入它,您需要在客戶端上切換到createRoot,然后開始使用。(https://github.com/reactwg/react-18/discussions/5

          要了解這些功能的作用以及它們?nèi)绾谓鉀Q上述問(wèn)題,讓我們返回到我們的示例。



          在獲取所有數(shù)據(jù)之前?流式傳輸 HTML

          使用現(xiàn)有的 SSR,渲染HTML和水化是“全有或全無(wú)”。首先渲染所有HTML:
          <main>  <nav>        <a href="/">Homea>   nav>  <aside>        <a href="/profile">Profilea>  aside>  <article>        <p>Hello worldp>  article>  <section>        <p>First commentp>    <p>Second commentp>  section>main>
          客戶端最終將會(huì)展示為:

          然后加載所有代碼并為整個(gè)應(yīng)用程序注入水分:

          但是React 18 給了你一個(gè)新的可能。您可以用??包裹頁(yè)面的一部分。

          例如,讓我們包裝注釋塊并告訴 React,在它準(zhǔn)備好之前,React 應(yīng)該顯示該組件:

            <NavBar />  <Sidebar />  <RightPane>    <Post />    <Suspense fallback={<Spinner />}>      <Comments />    Suspense>  RightPane>Layout>

          包裝成,我們告訴 React它不需要等待評(píng)論開始為頁(yè)面的其余部分流式傳輸 HTML。相反,React 將發(fā)送占位符(一個(gè)微調(diào)器)而不是評(píng)論:

          現(xiàn)在在最初的HTML中找不到注釋:
          <main>  <nav>        <a href="/">Homea>   nav>  <aside>        <a href="/profile">Profilea>  aside>  <article>        <p>Hello worldp>  article>  <section id="comments-spinner">        <img width=400 src="spinner.gif" alt="Loading..." />  section>main>

          故事到這里還沒(méi)有結(jié)束。當(dāng)評(píng)論的數(shù)據(jù)在服務(wù)器上準(zhǔn)備好時(shí),React會(huì)將額外的 HTML 發(fā)送到同一個(gè)流中,以及一個(gè)最小的內(nèi)聯(lián)

          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    波多野结衣成人在线视频 | 日本不卡清清视频 | 444iii日韩 | www.三级网站 | 91麻豆精产国品 |