React渲染機(jī)制及相關(guān)優(yōu)化方案

目錄 一、react渲染步驟 二、concurrent機(jī)制以及產(chǎn)生作用的機(jī)會(huì) 1. 優(yōu)先級(jí)調(diào)度: 2. 遞增式渲染: 三、簡單模擬實(shí)現(xiàn) concurrent mode 的遞增式渲染 四、與優(yōu)先級(jí)調(diào)度有關(guān)的兩個(gè)hooks 1. useTran
目錄
  • 一、react渲染步驟
  • 二、concurrent機(jī)制以及產(chǎn)生作用的機(jī)會(huì)
    • 1. 優(yōu)先級(jí)調(diào)度:
    • 2. 遞增式渲染:
  • 三、簡單模擬實(shí)現(xiàn) concurrent mode 的遞增式渲染
    • 四、與優(yōu)先級(jí)調(diào)度有關(guān)的兩個(gè)hooks
      • 1. useTransition
      • 2. useDeferredValue
      • 3. useTransition 與 useDeferredValue 的區(qū)別
      • 4. 應(yīng)用場景
    • 五、一個(gè)小例子
      • 1. 下面使用 useTransition 進(jìn)行優(yōu)化
      • 2. 使用 useDeferredValue 進(jìn)行優(yōu)化
    • 補(bǔ)充:為什么VUE不需要設(shè)計(jì) Concurrent Mode

      一、react渲染步驟

      • 準(zhǔn)備階段(Prepare?Phase)
        在準(zhǔn)備階段,React 會(huì)收集組件的依賴關(guān)系,建立組件樹的數(shù)據(jù)結(jié)構(gòu),確定組件的更新優(yōu)先級(jí),并生成用于渲染的工作單元。

      • 計(jì)算階段(Compute Phase)
        在計(jì)算階段,React 會(huì)根據(jù)組件的更新優(yōu)先級(jí)和調(diào)度策略,將工作單元分成多個(gè)批次進(jìn)行處理。每個(gè)批次都會(huì)執(zhí)行一小部分工作單元,以保證用戶界面的響應(yīng)性。

      • 渲染階段(Render Phase)
        在渲染階段,React 會(huì)根據(jù)工作單元的類型和優(yōu)先級(jí),執(zhí)行相應(yīng)的渲染操作。這包括創(chuàng)建新的虛擬 DOM 節(jié)點(diǎn)、更新現(xiàn)有的虛擬 DOM 節(jié)點(diǎn),以及卸載不再需要的組件。

      • 提交階段(Commit Phase)
        在提交階段,React 會(huì)將更新后的虛擬 DOM 節(jié)點(diǎn)映射到實(shí)際的 DOM,更新用戶界面。這個(gè)階段還會(huì)執(zhí)行一些副作用操作,如執(zhí)行useEffect。

      二、concurrent機(jī)制以及產(chǎn)生作用的機(jī)會(huì)

      注:React 的并發(fā)模式(Concurrency Mode)是一種用于處理大型和復(fù)雜應(yīng)用程序的特性,旨在提高應(yīng)用程序的性能和響應(yīng)能力。解決react中狀態(tài)更新就會(huì)觸發(fā)該組件及該組件下所有子組件無腦更新而引發(fā)的性能問題;同時(shí)提供部分控制作業(yè)調(diào)度優(yōu)先級(jí)的能力給開發(fā)者使用

      • 在傳統(tǒng)的 React 渲染模式中,更新操作是同步進(jìn)行的,即在進(jìn)行更新時(shí),會(huì)立即進(jìn)行組件的重新渲染,可能會(huì)阻塞主線程,導(dǎo)致頁面響應(yīng)變慢或失去響應(yīng)出現(xiàn)掉幀問題。

      • 而concurrent mode通過引入一種新的調(diào)度算法和優(yōu)先級(jí)機(jī)制,將更新操作劃分為多個(gè)優(yōu)先級(jí),使得 React 可以更好地管理和分配任務(wù),以實(shí)現(xiàn)更平滑的用戶體驗(yàn)。

      • concurrent mode主要具備以下幾個(gè)特性:異步渲染、優(yōu)先級(jí)調(diào)度、遞增式渲染

      補(bǔ)充:concurrent mode 主要工作在渲染流程的 Compute Phase 及 Render Phase,因?yàn)樗鼈兪羌兇獾?JS 計(jì)算意味著可以被拆分,而 commit 階段由于帶有 DOM 更新,不可能 DOM 變更到一半中斷,因此必須一次性執(zhí)行完成

      1. 優(yōu)先級(jí)調(diào)度:

      concurrent mode 通過對任務(wù)進(jìn)行優(yōu)先級(jí)劃分,React 可以根據(jù)優(yōu)先級(jí)動(dòng)態(tài)地分配和重新分配任務(wù)。基于此React 可以更好地響應(yīng)用戶交互和其他高優(yōu)先級(jí)的任務(wù),同時(shí)提供了 “useDeferredValue” 、“useTransition” 兩個(gè)hooks用于調(diào)度作業(yè)任務(wù)的優(yōu)先級(jí)。

      2. 遞增式渲染:

      1)concurrent mode 下的渲染是逐步進(jìn)行的,React 將大量需要重新渲染的組件的工作基于時(shí)間片的理念劃分為多個(gè)小片段工作,在瀏覽器的每一幀的空閑時(shí)間中去執(zhí)行這些渲染工作,而不是一下子全部直接執(zhí)行,這樣有效的避免了掉幀情況的出現(xiàn)。

      2)這里也就說明了為什么React官方說 componentWillMount 可能被調(diào)用多次的原因,正是因?yàn)榈蛢?yōu)先級(jí)任務(wù)的 render 階段可能被重復(fù)的中斷和重新執(zhí)行,而 componentWillMount 就包含在 render 階段中。

      注意:工作拆分的最小單元應(yīng)該是一個(gè)fiber節(jié)點(diǎn),當(dāng)某個(gè)fiber節(jié)點(diǎn)本身的計(jì)算就十分巨大時(shí)依然會(huì)導(dǎo)致卡幀,不過我們可以通過調(diào)整工作的優(yōu)先級(jí)使得用戶的體驗(yàn)是平滑的

      三、簡單模擬實(shí)現(xiàn) concurrent mode 的遞增式渲染

      • 下面使用 requestIdleCallback 函數(shù)模擬時(shí)間片,在每一幀的空閑時(shí)間進(jìn)行js計(jì)算從而達(dá)到遞增式渲染的效果

      index.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
          <script src="http://news.558idc.com/index.js"></script>
      </head>
      <body>
          <div id="root"></div>
          <script>
              // 調(diào)用render提供掛載容器 "root"
              render(document.getElementById('root'))
          </script>
      </body>
      </html>

      index.js

      // 頁面需要渲染的組件
      function Counter() {
          return {
              type: 'span',
              value: 'hello world',
              next: {
                  type: 'p',
                  value: 'hello LiHua'
              }
          }
      }
      const CounterElementDescriptors = {
          type: 'Function',
          fn: Counter
      }
      // 記錄當(dāng)前工作
      let presentWork = null
      // 記錄根元素
      let rootElementDescriptor = null    
      // 記錄掛載容器 
      let elementsContainer = null    
      // 處理單元任務(wù)
      function performUnitOfWork(deadline) {
          // 判斷當(dāng)前是否還有待執(zhí)行任務(wù)
          if (presentWork == null) return commitRoot(rootElementDescriptor)
          // 當(dāng)前幀超時(shí),調(diào)用 requestIdleCallback 把任務(wù)推到下一幀空閑時(shí)間執(zhí)行
          if (deadline.didTimeout) return requestIdleCallback(executeWorkLoop)
          // 若是組件則處理依賴關(guān)系、若是元素則生成真實(shí)dom
          if (presentWork.type === "Function") {
              rootElementDescriptor = presentWork
              const firstChildren = presentWork.fn()
              firstChildren.parent = presentWork
              presentWork.children = firstChildren
              presentWork = firstChildren
              performUnitOfWork(deadline)
          } else {
              const dom = document.createElement(presentWork.type)
              dom.innerHTML = presentWork.value
              presentWork.dom = dom
              presentWork = presentWork.next
              performUnitOfWork(deadline)
          }
      }
      // 控制循環(huán)執(zhí)行工作
      function executeWorkLoop(deadline) {
          performUnitOfWork(deadline)
      }
      // 提供render函數(shù),用于獲取掛載容器和開始渲染計(jì)算工作
      function render(element) {
          elementsContainer = element
          presentWork = CounterElementDescriptors
          requestIdleCallback(executeWorkLoop)
      }
      // 模擬commit階段
      function commitRoot(rootElement) {
          let renderCHildrenElements = rootElement.children
          do {
              elementsContainer.appendChild(renderCHildrenElements.dom)
              renderCHildrenElements = renderCHildrenElements.next
          }while(renderCHildrenElements)
      }

      四、與優(yōu)先級(jí)調(diào)度有關(guān)的兩個(gè)hooks

      1. useTransition

      官方解釋:useTransition 是一個(gè)讓你在不阻塞 UI 的情況下來更新狀態(tài)的 React Hook。

      • 通過 useTransition 我們可以將一部分的狀態(tài)更新工作劃分為低優(yōu)先級(jí)的異步任務(wù),使它不阻塞主要任務(wù)的執(zhí)行
      • 同時(shí)我們可以依據(jù) useTransition 返回的標(biāo)志狀態(tài)在渲染期間優(yōu)雅地展示加載狀態(tài),從而提高用戶界面的交互體驗(yàn)和流暢性
      • useTransition 主要語法如下:
      import { useTransition } from "react";
      function TabContainer() {
          // isPending 標(biāo)志,告訴你是否存在待處理的低優(yōu)先級(jí)工作。
          // startTransition 函數(shù) 允許你將該部分的狀態(tài)更新標(biāo)記為低優(yōu)先級(jí)。
          const [isPending, startTransition] = useTransition();
          function handle() {
              startTransition(() => {
                  // 低優(yōu)先級(jí)的狀態(tài)更新工作
                  {......}
              });
          }
          return (
              {......}
          )
      }

      2. useDeferredValue

      官方解釋:useDeferredValue 是一個(gè) React Hook,可以讓你延遲更新 UI 的某些部分。

      • 通過 useDeferredValue 我們可以將一部分的UI更新工作劃分為低優(yōu)先級(jí)的任務(wù),使它不阻塞主要任務(wù)的執(zhí)行
      • useTransition 主要語法如下:
      import { useDeferredValue, useState, } from "react";
      function TabContainer() {
          const [query, setQuery] = useState('');
          // 定義的 deferredQuery 獲取的是query的延遲版本
          const deferredQuery = useDeferredValue(query);
          function handle(data) {
              setQuery(data)
          }
          return (
          	<>
          		<List listData={deferredQuery} />
          		{ ......}
          	</>
          )
      }

      3. useTransition 與 useDeferredValue 的區(qū)別

      • useTransition 用于控制過渡狀態(tài),可以在過渡狀態(tài)中執(zhí)行任務(wù),并提供過渡狀態(tài)的布爾值來判斷是否處于過渡狀態(tài)。
      • useDeferredValue 用于延遲某個(gè)值的更新,以避免在渲染過程中處理昂貴的計(jì)算或數(shù)據(jù)獲取,確保界面的流暢性。
      • 雖然它們都與并發(fā)模式相關(guān),但用途和作用略有不同,具體使用哪一個(gè)需要看具體場景。

      4. 應(yīng)用場景

      1)長列表渲染:當(dāng)渲染大量列表項(xiàng)時(shí),可以對列表項(xiàng)的渲染任務(wù)調(diào)節(jié)為低優(yōu)先級(jí)異步任務(wù),以保證用戶界面的響應(yīng)性能。

      2)大型表單處理:對于包含大量輸入字段的表單,可以使用合理使用對于hooks將表單提交和驗(yàn)證等任務(wù)進(jìn)行優(yōu)化調(diào)節(jié),以避免阻塞用戶界面。

      3)圖片懶加載:當(dāng)頁面中包含大量圖片時(shí),可以使用 useTransition 將圖片的加載劃分為多個(gè)低優(yōu)先級(jí)異步任務(wù),在渲染期間逐步加載圖片,以減少對用戶界面的阻塞。

      4)異步數(shù)據(jù)加載:當(dāng)頁面中的數(shù)據(jù)需要從后端異步加載時(shí),可以使用 useTransition 將數(shù)據(jù)的加載劃分為多個(gè)異步任務(wù),以保證用戶界面的響應(yīng)性能。

      五、一個(gè)小例子

      • 以下以長列表渲染為例子做演示

      基礎(chǔ)代碼,未作優(yōu)化處理:

      import React, { useCallback, useState } from 'react'
      const index: React.FC = () => {
          const [list, setList] = useState<any[]>([])
          const handleSearch = useCallback((value: string) => {
                  const newList = []
                  for (let i = 0; i < 5000; i++) {
                      newList.push(value + '-' + i)
                  }
                  setList(newList)
          }, [])
          return (
              <>
                  <input onChange={(e) => handleSearch(e.target.value)} type='text' />
                  <div>
                      {list.map(item => <div key={item}>數(shù)據(jù)項(xiàng):{item}</div>)}
                  </div>
              </>
          )
      }
      export default index

      當(dāng)我們進(jìn)行持續(xù)的輸入時(shí)是十分的卡頓的,效果如下:

      1. 下面使用 useTransition 進(jìn)行優(yōu)化

      • 降低 “setList(newList)” 的優(yōu)先級(jí),使其不阻塞用戶輸入事件的觸發(fā)

      代碼修改如下:

      import React, { useCallback, useState, useTransition } from 'react'
      const index: React.FC = () => {
          const [list, setList] = useState<any[]>([])
          const [isPending, startTransition] = useTransition()
          const handleSearch = useCallback((value: string) => {
              startTransition(() => {
                  const newList = []
                  for (let i = 0; i < 5000; i++) {
                      newList.push(value + '-' + i)
                  }
                  setList(newList)
              })
          }, [])
          return (
              <>
                  <input onChange={(e) => handleSearch(e.target.value)} type='text' />
                  <div>
                      {isPending? '加載中。。。' : list.map(item => <div key={item}>數(shù)據(jù)項(xiàng):{item}</div>)}
                  </div>
              </>
          )
      }
      export default index

      優(yōu)化后效果如下:

      2. 使用 useDeferredValue 進(jìn)行優(yōu)化

      • 降低 “列表部分UI” 更新渲染的優(yōu)先級(jí),使其不阻塞用戶輸入事件的觸發(fā)

      代碼修改如下:

      import React, { memo, useDeferredValue, useState } from 'react'
      const Item = ({ text }: any) => {
          return (
              <div>
                  數(shù)據(jù)項(xiàng):{text}
              </div>
          )
      }
      const List = memo(({ inputValue }: { inputValue: string }) => {
          let items = [];
          for (let i = 0; i < 5000; i++) {
              items.push(<Item key={i} text={inputValue + '-' + i} />);
          }
          return (
              <>
                  {items}
              </>
          );
      })
      const index: React.FC = () => {
          const [inputValue, setInputValue] = useState('')
          const deferredInputValue = useDeferredValue(inputValue)
          return (
              <>
                  <input value={inputValue} onChange={(e) => setInputValue(e.target.value)} type='text' />
                  <List inputValue={deferredInputValue} />
              </>
          )
      }
      export default index

      優(yōu)化后效果如下:

      補(bǔ)充:為什么VUE不需要設(shè)計(jì) Concurrent Mode

      • 出于vue響應(yīng)式系統(tǒng)的設(shè)計(jì)實(shí)現(xiàn)思路的不同,也就體現(xiàn)了為什么。

      1)在vue中,響應(yīng)式系統(tǒng)通過 proxy 實(shí)現(xiàn)對 render函數(shù) 的依賴收集和觸發(fā)更新,基于追蹤組件依賴的響應(yīng)式數(shù)據(jù)的變化,可以更為精準(zhǔn)的實(shí)現(xiàn)組件的更新,大大避免了不必要的渲染和更新操作,規(guī)避了react中狀態(tài)更新就會(huì)觸發(fā)組件及該組件下所有子組件無腦更新的問題。

      2)同時(shí)vue的異步更新策略也有助于提高性能和響應(yīng)能力。Vue會(huì)在下一個(gè)事件循環(huán)周期中批量更新組件,這樣可以避免頻繁的DOM操作和重復(fù)渲染,提高渲染效率。

      3)但vue中暫時(shí)沒有 useTransition 和 useDeferredValue 類似的功能操作,無法調(diào)度控制作業(yè)的優(yōu)先級(jí)

      以上就是React渲染機(jī)制及相關(guān)優(yōu)化方案的詳細(xì)內(nèi)容,更多關(guān)于React渲染機(jī)制的資料請關(guān)注技圈網(wǎng)其它相關(guān)文章!

      聲明:所有內(nèi)容來自互聯(lián)網(wǎng)搜索結(jié)果,不保證100%準(zhǔn)確性,僅供參考。如若本站內(nèi)容侵犯了原著者的合法權(quán)益,可聯(lián)系我們進(jìn)行處理。
      發(fā)表評論
      更多 網(wǎng)友評論0 條評論)
      暫無評論

      返回頂部

      主站蜘蛛池模板: 一二三四视频日本高清| 免费精品久久天干天干| 久久国产精品一区免费下载| 亚洲一区二区三区在线网站| 欧美性xxxx极品hd欧美风情| 国产高清www免费视频| 亚洲视频在线看| ntr出差上司灌醉女职员电影| 精品卡2卡3卡4卡免费| 孕妇videos孕交| 免费人成在线观看网站品爱网| 一区二区三区中文| 狠狠精品久久久无码中文字幕| 多毛bgmbgmbgm胖在线| 亚洲第一网站男人都懂| 97久视频精品视频在线老司机| 毛片试看120秒| 国产精品无码av天天爽| 亚洲中文字幕无码久久| 欧美videos极品| 日韩欧美中文字幕在线播放| 国产伦精品一区二区三区视频小说| 久久久久人妻一区精品色欧美| 色噜噜噜噜亚洲第一| 成人性生交大片免费看好| 免费无码va一区二区三区| 99久久99久久精品国产片果冻| 欧美日韩一区二区三区四区在线观看| 国产综合久久久久久鬼色| 亚洲av专区无码观看精品天堂 | 欧美一级三级在线观看| 国产精品成人99一区无码| 五月天六月丁香| 草莓视频黄瓜视频| 性色爽爱性色爽爱网站| 人人妻人人爽人人澡人人| 99久久免费看国产精品| 果冻传媒电影在线| 国产一区二区日韩欧美在线| va亚洲va欧美va国产综合| 欧美成人精品第一区二区三区|