日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

理解這個機制,是成為React性能優化高手的關鍵

來源: 責編: 時間:2024-01-16 10:14:01 274觀看
導讀本來是準備優先分享兩個官方定義的 Hook useMemo,useCallback,不過這兩個 hook 本身其實沒有太多探討的空間,他們只是兩個記憶函數,本身并沒有特殊的、更進一步的含義。許多人的困惑往往來源于對于它們兩個過度解讀,認為他

Y9a28資訊網——每日最新資訊28at.com

本來是準備優先分享兩個官方定義的 Hook useMemo,useCallback,不過這兩個 hook 本身其實沒有太多探討的空間,他們只是兩個記憶函數,本身并沒有特殊的、更進一步的含義。Y9a28資訊網——每日最新資訊28at.com

許多人的困惑往往來源于對于它們兩個過度解讀,認為他們的存在對 React 性能的優化有非常重要的意義。過渡解讀導致了對他們的濫用。在我看過的項目中,有個別優秀前端團隊里的項目規范里,也錯誤抬高了他們的作用,把他們用在了每一個組件里。Y9a28資訊網——每日最新資訊28at.com

出現這樣問題的根源就在于對 React 的自身機制理解不夠精準。因此我決定換一個角度去帶大家理解 React 本身的優化機制,從而能夠正確的使用 useMemo 與 useCallback。Y9a28資訊網——每日最新資訊28at.com

本文將會從應用層面來為大家分析我們應該怎么做。后續的章節將會從 Fiber 的雙緩存策略開始分享底層的優化機制。Y9a28資訊網——每日最新資訊28at.com

一、精簡節點

首先我們要明確一些前置知識。Y9a28資訊網——每日最新資訊28at.com

React 在內存中維護了一顆 虛擬 DOM 樹,這顆樹的每一個節點是一個 Fiber,每一個 Fiber 都由 JSX 中的組件解析而來。Y9a28資訊網——每日最新資訊28at.com

type Fiber = {  // 用于標記fiber的WorkTag類型,主要表示當前fiber代表的組件類型如FunctionComponent、ClassComponent等  tag: WorkTag,  // ReactElement里面的key  key: null | string,  // ReactElement.type,調用`createElement`的第一個參數  elementType: any,  // The resolved function/class/ associated with this fiber.  // 表示當前代表的節點類型  type: any,  // 表示當前FiberNode對應的element組件實例  stateNode: any,  // 指向他在Fiber節點樹中的`parent`,用來在處理完這個節點之后向上返回  return: Fiber | null,  // 指向自己的第一個子節點  child: Fiber | null,  // 指向自己的兄弟結構,兄弟節點的return指向同一個父節點  sibling: Fiber | null,  index: number,  ref: null | (((handle: mixed) => void) & { _stringRef: ?string }) | RefObject,  // 當前處理過程中的組件props對象  pendingProps: any,  // 上一次渲染完成之后的props  memoizedProps: any,  // 該Fiber對應的組件產生的Update會存放在這個隊列里面  updateQueue: UpdateQueue<any> | null,  // 上一次渲染的時候的state  memoizedState: any,  // 一個列表,存放這個Fiber依賴的context  firstContextDependency: ContextDependency<mixed> | null,  mode: TypeOfMode,  // Effect  // 用來記錄Side Effect  effectTag: SideEffectTag,  // 單鏈表用來快速查找下一個side effect  nextEffect: Fiber | null,  // 子樹中第一個side effect  firstEffect: Fiber | null,  // 子樹中最后一個side effect  lastEffect: Fiber | null,  // 代表任務在未來的哪個時間點應該被完成,之后版本改名為 lanes  expirationTime: ExpirationTime,  // 快速確定子樹中是否有不在等待的變化  childExpirationTime: ExpirationTime,  // fiber的版本池,即記錄fiber更新過程,便于恢復  alternate: Fiber | null,}

state 的每次變化,都會引發整棵樹的前后對比,從而導致許多組件重新執行。這也是 React 性能消耗的主要成本。但是 React 內部采用緩存機制和優秀的 Diff 算法極大的減少了這里的成本,后續我們會詳細介紹這兩個機制。Y9a28資訊網——每日最新資訊28at.com

這里我要重點介紹的是,在使用中,我們可以通過減小這顆 Fiber tree 的方式來達到性能優化的目的。只要 Fiber tree 足夠小,diff 的成本就會非常的低。Y9a28資訊網——每日最新資訊28at.com

例如,我們有一個非常大的巨石項目,當我們路由切換的時候,會直接刪掉前一個頁面的所有內容,只渲染新頁面的內容,那么,雖然隨著訪問頁面的數量越來越多,緩存在全局狀態管理器中的數據越來越復雜,但是 Fiber tree 的大小其實并沒有變得越來越大,依然維持在一個頁面的量級,此時的 diff 壓力跟一個小型項目沒有什么區別。通過這種手段,我們可以輕松保持一個巨石項目的高性能。Y9a28資訊網——每日最新資訊28at.com

落實到具體的頁面上,特別是在一些管理系統里,許多開發者喜歡在在列表頁中,維護一個內容超級復雜的彈窗組件,彈窗的內容是列表的詳情。此時,彈窗內容和列表內容同時存在,從而導致了 Fiber tree 的龐大。Y9a28資訊網——每日最新資訊28at.com

從交互上,我們可以將復雜的彈窗內容移植到一個新的詳情頁,就能極大的緩解 diff 壓力。Y9a28資訊網——每日最新資訊28at.com

在某些項目中,一個詳情頁有幾百條表單需要填寫。我們可以通過分步驟的方式,把這幾百個表單項切分到不同的步驟里,從而讓同時渲染出來的表單項大量減少,性能也會有很大的提高。Y9a28資訊網——每日最新資訊28at.com

總的來說,只要我們把 Fiber 節點數量控制在一定范圍內,React 都能保持一個非常高的性能。因此大多數情況下,我們并不需要做額外的性能優化。Y9a28資訊網——每日最新資訊28at.com

二、比較方式

由于大量的 re-render 存在,我們很容易能想到一個優化策略,在 diff 過程中,當我比較之后發現有的節點并沒有發生任何變化,那么我們就可以跳過該組件的 re-render,從而提高性能。Y9a28資訊網——每日最新資訊28at.com

而要讓這個優化想法落地,我們就必須了解內部的比較規則,首先要考慮的第一個問題就是。Y9a28資訊網——每日最新資訊28at.com

如何知道一個組件是否發生了變化

一個 React 組件是否發生了變化由三個因素決定。Y9a28資訊網——每日最新資訊28at.com

  • props
  • state
  • context

這三個因素中的任何一個發生了變化,組件都會認為自己應該發生變化。state 和 context 都是不可變數據,而且由于是我們主動調用 dispatch 去觸發他們發生改變,因此 state 和 context 的變化一般不會對我們造成理解上的困擾。Y9a28資訊網——每日最新資訊28at.com

最麻煩的是 props。Y9a28資訊網——每日最新資訊28at.com

React 組件的每次執行,都會傳入新的 props 對象,雖然內容可能一樣,但是在內存中卻已經發生了變化。Y9a28資訊網——每日最新資訊28at.com

function Child(props) {}// 執行一次傳入新的對象Child({})// 執行一次傳入新的對象Child({})

與 state 不一樣的是,props 并沒有緩存在別的地方,因此,一個組件 的 props 哪怕什么都沒有變化,比較的結果也是 false。Y9a28資訊網——每日最新資訊28at.com

var preProps = {}var curProps = {}preProps === curProps // false
var preProps = { name: 'Jake' }var curProps = { name: 'Jake' }preProps === curProps // false

呵!沒想到吧。Y9a28資訊網——每日最新資訊28at.com

也就是說,當一個子組件接收一個函數作為 props,為了保證函數的引用不發生變化,有的人選擇使用 useCallback 來緩存函數引用,從而期望子組件不會因為 props 發生了變化而導致子組件重新渲染。Y9a28資訊網——每日最新資訊28at.com

function Demo() {  ...  const change = useCallback(() => {}, [])  return (    <div>      ...      <Filter change={change} />    </div>  )}

結合我們剛才說的,這里只使用 useCallback 是做了無用功。Y9a28資訊網——每日最新資訊28at.com

preProps = { change: change }curProps = { change: change }preProps === curProps // false

那么問題就來了,如果這樣子的話,豈不是每個組件的 props 都會發生變化了?Y9a28資訊網——每日最新資訊28at.com

當然不是,React 內部針對 props 有另外一個策略:Y9a28資訊網——每日最新資訊28at.com

如果父組件被判定為沒有變化,那么,在判斷子組件是否發生變化時,不會比較子組件的 props。Y9a28資訊網——每日最新資訊28at.com

源碼里少一個判斷,卻衍生出這樣一個精妙的設計。Y9a28資訊網——每日最新資訊28at.com

高級!Y9a28資訊網——每日最新資訊28at.com

除此之外,Fiber Tree 的根節點,被判定為始終不會發生變化。Y9a28資訊網——每日最新資訊28at.com

這樣,根節點的子組件在比較時,react 就一定會跳過 props 的比較,以此類推。我們就有機會構造一個高性能的更新過程。Y9a28資訊網——每日最新資訊28at.com

回到我們經典的數字遞增案例,來分析這個案例。Y9a28資訊網——每日最新資訊28at.com

function Child() {  console.log('我不想重新渲染')    return (    <div>我不想重新渲染</div>  )}export default function Demo02() {  const [count, setCount] = useState(0)  return (    <div className="wrapper">      <div onClick={() => setCount(count + 1)}>{count}</div>      <Child />    </div>  )}

當我們點擊數字的時候,數字遞增,父組件 Demo02 被判定為改變,因此,內部的所有子組件都需要比較 props,props 為不可變數據,子組件 Child 的 props 進行了如下比較,結果為 false 。Y9a28資訊網——每日最新資訊28at.com

{} === {} // false

因此,Child 雖然不想 re-render,但是每次 count 變化都 render 了。Y9a28資訊網——每日最新資訊28at.com

調整的方式非常簡單,只需要讓父組件的 state 沒有發生變化即可,把變化的部分單獨封裝在另外一個子組件里。Y9a28資訊網——每日最新資訊28at.com

function Change() {  const [count, setCount] = useState(0)  return (    <div onClick={() => setCount(count + 1)}>{count}</div>  )}export default function Demo02() {  return (    <div className="wrapper">      <Change />      <Child />    </div>  )}

這個時候,父組件被判定為沒有發生變化,因此子組件就會跳過 props 的比較,從而 Child 判定為沒有發生變化。這樣我們的目的就達到了。Y9a28資訊網——每日最新資訊28at.com

但是,這里有一個前期條件,那就是我們需要確保 Demo02 的父組件也被判定為沒有發生變化,因此,如果你是 React 架構師,頂層結構的設計是你需要關注的重中之重,因為如果頂層出了問題,導致父組件不滿足這樣的穩定結構,那么后續的子組件都會 re-render。Y9a28資訊網——每日最新資訊28at.com

那么理解這個規則很難嗎?其實不難,難就難在,在看這篇文章之前,可能你壓根就不知道這個設計啊。Y9a28資訊網——每日最新資訊28at.com

如果我們有一個不靠譜的 React 架構師,頂層組件的穩定結構出了問題,那么我們有什么手段,能夠低成本的讓你能接觸到的頁面結構保持穩定呢?Y9a28資訊網——每日最新資訊28at.com

答案就是 React.memo。Y9a28資訊網——每日最新資訊28at.com

memo 函數會讓組件的 props 比較方式發生變化,我們之前都是一直用的 === 全等比較,使用 memo 包裹組件之后,React 內部會改變比較策略,他會遍歷 props 的每個屬性,如果每個屬性都能通過全等比較,那么就判定為 props 沒有發生變化。Y9a28資訊網——每日最新資訊28at.com

這個遍歷過程只會發生在 props 對象的第一層屬性,不會更進一步深入。Y9a28資訊網——每日最新資訊28at.com

因此,當我們無法確定上層組件是否發生變化時,我們可以在某一個節點使用 memo 來確保從這一層開始建立穩定的高性能模式。Y9a28資訊網——每日最新資訊28at.com

function _Child() {  console.log('我不想重新渲染')    return (    <div>我不想重新渲染</div>  )}var Child = memo(_Child)export default function Demo02() {  const [count, setCount] = useState(0)  return (    <div className="wrapper">      <div onClick={() => setCount(count + 1)}>{count}</div>      <Child />    </div>  )}

當我們使用 memo 包裹子組件導致 props 的比較方式發生變化時,useCallback 緩存引用就有用了。這也是 useCallback 的主要作用,他一定要結合 memo 去使用。Y9a28資訊網——每日最新資訊28at.com

當然,我們也可以用一些騷操作來達到同樣的目標,利用 useMemo 來緩存組件。Y9a28資訊網——每日最新資訊28at.com

export default function Demo02() {  const [count, setCount] = useState(0)  const _child = useMemo(() => {    return <Child />  }, [])  return (    <div className="wrapper">      <div onClick={() => setCount(count + 1)}>{count}</div>      {_child}    </div>  )}

當你決定要自己設計比較規則時就可以采用這樣的方式。Y9a28資訊網——每日最新資訊28at.com

三、總結

這篇文章分享了兩個 React 項目性能優化的最重要的手段。我們只要了解了真實的底層機制,就能寫出高性能的代碼,他們的理解難度并不高。我們只需要在項目中正確的去編寫符合他們機制的代碼即可。Y9a28資訊網——每日最新資訊28at.com

如果你是 React 項目架構師,那么你一定要吃透這個機制,在頂層架構中,我們會額外添加 Router/Redux 等諸多頂層組件,他們會不會導致高性能結構的崩塌,你一定要非常明確。Y9a28資訊網——每日最新資訊28at.com

除此之外,當頂層的父組件不變判定被破壞,我們也不需要每一個組件都用 memo 包裹起來,只需要在合適的節點包裹一個組件即可。因為 memo 的比較本身也會增加程序的執行成本,大量的 memo 反而會導致性能變得更低。Y9a28資訊網——每日最新資訊28at.com

除此之外,我們要明確,組件的 re-render 是內存行為,他是執行了一次 JS 函數,他并不會導致瀏覽器真的發生渲染行為,因此 re-render 的執行也是非常快速的,大多數情況下的 re-render 都可以接受,不過超大量的 re-render 會導致執行壓力變大,所以用大量 memo 減少 re-render 并不一定是一件劃算的事情。Y9a28資訊網——每日最新資訊28at.com

利用少量的 memo 與 React 本身的緩存機制減少大量的 re-render 才是合理的方案。Y9a28資訊網——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-62353-0.html理解這個機制,是成為React性能優化高手的關鍵

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Spring為什么建議構造器注入?看看和你所理解的一樣嗎?

下一篇: 部署過Vue項目嗎?遇到404如何解決?

標簽:
  • 熱門焦點
  • Find N3入網:最高支持16+1TB

    OPPO將于近期登場的Find N3折疊屏目前已經正式入網,型號為PHN110。本次Find N3在外觀方面相比前兩代有很大的變化,不再是小號的橫向折疊屏,而是跟別的廠商一樣采用了較為常見的
  • vivo TWS Air開箱體驗:真輕 臻好聽

    在vivo S15系列新機的發布會上,vivo的最新款真無線藍牙耳機vivo TWS Air也一同發布,本次就這款耳機新品給大家帶來一個簡單的分享。外包裝盒上,vivo TWS Air保持了vivo自家產
  • 女孩租房開2小時空調用完100元電費引熱議:5級能耗惹不起 月薪過萬電費也交不起

    近日,江蘇蘇州一女孩租房當天充值了100元電費,開著空調不到2小時發現電費已用完。對于為什么這個快,房東表示,電表壞了這種情況很多,之前也遇到過,給租客換
  • 0糖0卡0脂 旭日森林仙草烏龍茶優惠:15瓶到手29元

    旭日森林無糖仙草烏龍茶510ml*15瓶平時要賣為79.9元,今日下單領取50元優惠券,到手價為29.9元。產品規格:0糖0卡0脂,添加草本仙草汁,清涼爽口,富含茶多酚,保留
  • 三言兩語說透設計模式的藝術-簡單工廠模式

    一、寫在前面工廠模式是最常見的一種創建型設計模式,通常說的工廠模式指的是工廠方法模式,是使用頻率最高的工廠模式。簡單工廠模式又稱為靜態工廠方法模式,不屬于GoF 23種設計
  • 讓我們一起聊聊文件的操作

    文件【1】文件是什么?文件是保存數據的地方,是數據源的一種,比如大家經常使用的word文檔、txt文件、excel文件、jpg文件...都是文件。文件最主要的作用就是保存數據,它既可以保
  • 阿里大調整

    來源:產品劉有媒體報道稱,近期淘寶天貓集團啟動了近年來最大的人力制度改革,涉及員工績效、層級體系等多個核心事項,目前已形成一個初步的&ldquo;征求意見版&rdquo;:1、取消P序列
  • 華為舉行春季智慧辦公新品發布會 首次推出電子墨水屏平板

    北京時間2月27日晚,華為在巴塞羅那舉行春季智慧辦公新品發布會,在海外市場推出之前已經在中國市場上市的筆記本、平板、激光打印機等辦公產品,并首次推出搭載
  • 利用職權私自解除被封帳號 Meta開除20多名員工

    11月18日消息,據外媒援引知情人士表示,過去一年時間內,Facebook母公司Meta解雇或處罰了20多名員工以及合同工,指控這些人通過內部系統以不當方式重置用戶帳號,其
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
精品不卡一区二区三区| 蘑菇福利视频一区播放| 亚洲欧美日韩一区二区| 午夜久久久久久久久久一区二区| 欧美在线电影| 欧美+亚洲+精品+三区| 欧美日韩成人一区| 国产女主播一区二区| 一区二区三区中文在线观看 | 亚洲欧洲日产国码二区| 亚洲天堂网在线观看| 午夜久久tv| 欧美国产欧美亚洲国产日韩mv天天看完整 | 久久影院午夜论| 欧美日韩亚洲91| 国产亚洲精品高潮| 亚洲精品一区久久久久久 | 欧美波霸影院| 国产精品亚洲不卡a| 亚洲国产精品成人综合色在线婷婷 | 永久免费视频成人| 欧美性久久久| 国产一区二区日韩精品| 日韩一区二区福利| 久久久久久999| 国产精品久久久久久妇女6080| 一区二区视频欧美| 亚洲男人的天堂在线观看| 免费亚洲一区| 国产深夜精品| 一区二区三区黄色| 美女图片一区二区| 国产精品一二一区| 99热精品在线| 免费av成人在线| 国产免费亚洲高清| 日韩图片一区| 老司机免费视频一区二区三区 | 国内精品一区二区三区| 亚洲无人区一区| 欧美77777| 国产亚洲网站| 亚洲免费小视频| 欧美精品观看| 在线成人激情黄色| 欧美一区日韩一区| 国产精品国产| 夜夜嗨av一区二区三区网页| 久久夜色精品国产亚洲aⅴ| 国产麻豆综合| 亚洲一区二三| 欧美日韩视频在线一区二区观看视频| 亚洲高清资源| 久久全球大尺度高清视频| 国产女主播视频一区二区| 亚洲午夜电影网| 欧美人妖另类| 亚洲欧洲精品一区二区三区波多野1战4 | 一本色道久久综合亚洲精品高清| 久久一区精品| 国内精品伊人久久久久av一坑| 亚洲综合日韩在线| 国产精品啊v在线| 99视频在线观看一区三区| 欧美福利在线| 亚洲欧洲一区二区在线播放| 欧美~级网站不卡| 亚洲第一狼人社区| 久热精品视频在线免费观看| 韩国女主播一区二区三区| 欧美伊人久久| 国产日韩精品一区| 欧美一区二区日韩一区二区| 国产精品视频区| 亚洲尤物视频在线| 国产精品久久| 亚洲私人影院在线观看| 欧美性片在线观看| 亚洲一区二区成人在线观看| 亚洲欧美一区二区原创| 国产精品第三页| 亚洲影院色无极综合| 国产精品热久久久久夜色精品三区| 中日韩美女免费视频网站在线观看| 欧美日韩亚洲国产精品| 亚洲深夜福利在线| 国产精品国产三级国产普通话三级| 亚洲午夜一区| 国产精品狼人久久影院观看方式| 亚洲一区三区电影在线观看| 国产精品久久久999| 亚洲中字在线| 国产欧美日韩综合| 久久精品国产欧美激情| 影音先锋另类| 欧美久久久久久久| 亚洲视频在线看| 国产精品一二三| 久久成人羞羞网站| 在线观看成人网| 欧美激情1区| 这里只有精品在线播放| 国产精品视频免费| 久久久噜噜噜久久人人看| 亚洲电影观看| 欧美日韩亚洲在线| 欧美一区二区三区喷汁尤物| 狠狠色丁香久久综合频道| 久久综合久久综合九色| 91久久精品国产| 欧美色图一区二区三区| 香蕉成人伊视频在线观看| 激情自拍一区| 欧美日本乱大交xxxxx| 亚洲欧美日韩精品在线| 黑人极品videos精品欧美裸| 欧美福利视频| 亚洲欧美电影在线观看| 激情久久综合| 欧美日韩高清一区| 午夜精品久久久久久99热软件| 国内精品久久久久久 | 一区二区三区在线免费播放| 欧美激情精品久久久久久免费印度| 一区二区欧美亚洲| 国产色婷婷国产综合在线理论片a| 久久一区精品| 亚洲一区www| 在线播放中文字幕一区| 亚洲欧美激情在线视频| 尤物精品在线| 欧美天堂亚洲电影院在线播放| 性亚洲最疯狂xxxx高清| 亚洲国产另类久久精品| 国产精品久久久久7777婷婷| 久久婷婷影院| 亚洲手机视频| 亚洲大胆av| 国产精品美女久久久久久久 | 欧美三级电影网| 久久久久久穴| 亚洲视频高清| 在线成人免费观看| 国产精品久久久久久久9999| 免费不卡中文字幕视频| 亚洲欧美日韩电影| 亚洲经典三级| 国产一区二区三区视频在线观看| 欧美精品亚洲二区| 久久成人精品无人区| 日韩一级成人av| 黄色精品在线看| 国产精品久久久久av| 欧美不卡视频| 久久久久久久久久久久久9999| 中国av一区| 亚洲激情电影在线| 国产午夜精品久久久久久久| 欧美日韩国产a| 美女久久一区| 亚洲欧美一区二区精品久久久| 亚洲电影成人| 国产在线视频欧美一区二区三区| 欧美日韩中文字幕在线视频| 老司机成人网| 久久久久国产免费免费| 亚洲免费在线播放| 夜夜嗨av一区二区三区 | 久久久久一区二区三区| 亚洲免费人成在线视频观看| 亚洲精品欧洲| 亚洲国产成人91精品| 国产一级一区二区| 国产精品视频1区| 欧美日韩影院| 欧美日本亚洲韩国国产| 你懂的国产精品| 久久米奇亚洲| 久久久精品国产免费观看同学| 午夜精品久久久久久久久| 中日韩高清电影网| 一区二区黄色| 一区二区高清在线| 99成人免费视频| 亚洲免费观看高清完整版在线观看| 在线国产日韩| 在线成人av| 极品日韩久久| 红桃视频国产精品| 国内精品久久久久久影视8| 国产欧美日韩亚洲一区二区三区| 亚洲影视中文字幕| 中文av字幕一区| 一区二区三区www| 一区二区三区国产精华| 99re66热这里只有精品4| 亚洲日本欧美| 亚洲裸体俱乐部裸体舞表演av| 91久久精品美女高潮| 亚洲国产精品传媒在线观看| 伊人一区二区三区久久精品| 狠狠色丁香婷综合久久| 依依成人综合视频| 伊伊综合在线|