最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React中的Diff算法你了解嗎

 更新時(shí)間:2022年03月13日 17:24:22   作者:迪盧克的現(xiàn)任  
這篇文章主要為大家詳細(xì)介紹了React的Diff算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

一、Diff算法的作用

渲染真實(shí)DOM的開銷很大,有時(shí)候我們修改了某個(gè)數(shù)據(jù),直接渲染到真實(shí)dom上會(huì)引起整個(gè)dom樹的重繪和重排。我們希望只更新我們修改的那一小塊dom,而不是整個(gè)dom,diff算法就幫我們實(shí)現(xiàn)了這點(diǎn)。

diff算法的本質(zhì)就是:找出兩個(gè)對象之間的差異,目的是盡可能做到節(jié)點(diǎn)復(fù)用。

注:此處說到的對象,指的其實(shí)就是vue中的virtual dom(虛擬dom樹),即使用js對象來表示頁面中的dom結(jié)構(gòu)。

二、React的Diff算法  

1、什么是調(diào)和?

將Virtual DOM樹轉(zhuǎn)換成Actual DOM樹的最少操作的過程稱為調(diào)和。

2、什么是React diff算法?

diff算法是調(diào)和的具體實(shí)現(xiàn)。

3、diff策略

React用三大策略 將O(n3)復(fù)雜度 轉(zhuǎn)化為O(n)復(fù)雜度

(1)策略一tree diffWeb UI中DOM節(jié)點(diǎn)跨層級的移動(dòng)操作特別少,可以忽略不計(jì)。

(2)策略二component diff擁有相同類的兩個(gè)組件 生成相似的樹形結(jié)構(gòu),擁有不同類的兩個(gè)組件 生成不同的樹形結(jié)構(gòu)。

(3)策略三element diff對于同一層級的一組子節(jié)點(diǎn),通過唯一id區(qū)分。

4、tree diff:

(1)React通過updateDepthVirtual DOM樹進(jìn)行層級控制

(2)對樹分層比較,兩棵樹只對同一層次節(jié)點(diǎn)進(jìn)行比較。如果該節(jié)點(diǎn)不存在時(shí),則該節(jié)點(diǎn)及其子節(jié)點(diǎn)會(huì)被完全刪除,不會(huì)再進(jìn)一步比較。

(3)只需遍歷一次,就能完成整棵DOM樹的比較。

如果DOM 節(jié)點(diǎn)出現(xiàn)了跨層級操作,Diff會(huì)怎么辦?

答:Tree DIFF是對樹的每一層進(jìn)行遍歷,如果某組件不存在了,則會(huì)直接銷毀。如圖所示,左邊是舊屬,右邊是新屬,第一層是R組件,一模一樣,不會(huì)發(fā)生變化;第二層進(jìn)入Component DIFF,同一類型組件繼續(xù)比較下去,發(fā)現(xiàn)A組件沒有,所以直接刪掉A、B、C組件;繼續(xù)第三層,重新創(chuàng)建A、B、C組件。

如上圖所示,以A為根節(jié)點(diǎn)的整棵樹會(huì)被重新創(chuàng)建,而不是移動(dòng),因此 官方建議不要進(jìn)行DOM節(jié)點(diǎn)跨層級操作,可以通過CSS隱藏、顯示節(jié)點(diǎn),而不是真正地移除、添加DOM節(jié)點(diǎn)。

5、component diff :

React對不同的組件間的比較,有三種策略

(1)同一類型的兩個(gè)組件,按原策略(層級比較)繼續(xù)比較Virtual DOM樹即可。

(2)同一類型的兩個(gè)組件,組件A變化為組件B時(shí),可能Virtual DOM沒有任何變化,如果知道這點(diǎn)(變換的過程中,Virtual DOM沒有改變),可節(jié)省大量計(jì)算時(shí)間,所以用戶可以通過 shouldComponentUpdate() 來判斷是否需要判斷計(jì)算。

(3)不同類型的組件,將一個(gè)(將被改變的)組件判斷為dirtycomponent(臟組件),從而替換整個(gè)組件的所有節(jié)點(diǎn)。

 注意:如上圖所示,當(dāng)組件D變?yōu)榻M件G時(shí),即使這兩個(gè)組件結(jié)構(gòu)相似,一旦React判斷D和G是不用類型的組件,就不會(huì)比較兩者的結(jié)構(gòu),而是直接刪除組件D,重新創(chuàng)建組件G及其子節(jié)點(diǎn)。雖然當(dāng)兩個(gè)組件是不同類型但結(jié)構(gòu)相似時(shí),進(jìn)行diff算法分析會(huì)影響性能,但是畢竟不同類型的組件存在相似DOM樹的情況在實(shí)際開發(fā)過程中很少出現(xiàn),因此這種極端因素很難在實(shí)際開發(fā)過程中造成重大影響。

6、element diff 

當(dāng)節(jié)點(diǎn)處于同一層級時(shí),diff提供三種節(jié)點(diǎn)操作:刪除、插入、移動(dòng)。

插入組件 C 不在集合(A,B)中,需要插入

刪除:

(1)組件 D 在集合(A,B,D)中,但 D的節(jié)點(diǎn)已經(jīng)更改,不能復(fù)用和更新,所以需要?jiǎng)h除 舊的D ,再創(chuàng)建新的。

(2)組件D之前在集合(A,B,D)中,但集合變成新的集合(A,B)了,D 就需要被刪除。

移動(dòng):組件D已經(jīng)在集合(A,B,C,D)里了,且集合更新時(shí),D沒有發(fā)生更新,只是位置改變,如新集合(A,D,B,C),D在第二個(gè),無須像傳統(tǒng)diff,讓舊集合的第二個(gè)B和新集合的第二個(gè)D 比較,并且刪除第二個(gè)位置的B,再在第二個(gè)位置插入D,而是 (對同一層級的同組子節(jié)點(diǎn)) 添加唯一key進(jìn)行區(qū)分,移動(dòng)即可。

 移動(dòng)情形一:新舊集合中存在相同節(jié)點(diǎn)但位置不同時(shí),如何移動(dòng)節(jié)點(diǎn)

(1)B不移動(dòng),不贅述,更新l astIndex=1

(2)新集合取得 E,發(fā)現(xiàn)舊不存在,故在lastIndex=1的位置 創(chuàng)建E,更新lastIndex=1

(3)新集合取得C,C不移動(dòng),更新lastIndex=2

(4)新集合取得A,A移動(dòng),同上,更新lastIndex=2

(5)新集合對比后,再對舊集合遍歷。判斷 新集合 沒有,但 舊集合 有的元素(如D,新集合沒有,舊集合有),發(fā)現(xiàn) D,刪除D,diff操作結(jié)束。

React中Diff算法實(shí)現(xiàn)的代碼:

_updateChildren: function(nextNestedChildrenElements, transaction, context) {
    var prevChildren = this._renderedChildren;
    var removedNodes = {};
    var mountImages = [];
    // 獲取新的子元素?cái)?shù)組
    var nextChildren = this._reconcilerUpdateChildren(
      prevChildren,
      nextNestedChildrenElements,
      mountImages,
      removedNodes,
      transaction,
      context
    );
    if (!nextChildren && !prevChildren) {
      return;
    }
    var updates = null;
    var name;
    var nextIndex = 0;
    var lastIndex = 0;
    var nextMountIndex = 0;
    var lastPlacedNode = null;
    for (name in nextChildren) {
      if (!nextChildren.hasOwnProperty(name)) {
        continue;
      }
      var prevChild = prevChildren && prevChildren[name];
      var nextChild = nextChildren[name];
      if (prevChild === nextChild) {
        // 同一個(gè)引用,說明是使用的同一個(gè)component,所以我們需要做移動(dòng)的操作
        // 移動(dòng)已有的子節(jié)點(diǎn)
        // NOTICE:這里根據(jù)nextIndex, lastIndex決定是否移動(dòng)
        updates = enqueue(
          updates,
          this.moveChild(prevChild, lastPlacedNode, nextIndex, lastIndex)
        );
        // 更新lastIndex
        lastIndex = Math.max(prevChild._mountIndex, lastIndex);
        // 更新component的.mountIndex屬性
        prevChild._mountIndex = nextIndex;
      } else {
        if (prevChild) {
          // 更新lastIndex
          lastIndex = Math.max(prevChild._mountIndex, lastIndex);
        }
        // 添加新的子節(jié)點(diǎn)在指定的位置上
        updates = enqueue(
          updates,
          this._mountChildAtIndex(
            nextChild,
            mountImages[nextMountIndex],
            lastPlacedNode,
            nextIndex,
            transaction,
            context
          )
        );
        nextMountIndex++;
      }
      // 更新nextIndex
      nextIndex++;
      lastPlacedNode = ReactReconciler.getHostNode(nextChild);
    }
    // 移除掉不存在的舊子節(jié)點(diǎn),和舊子節(jié)點(diǎn)和新子節(jié)點(diǎn)不同的舊子節(jié)點(diǎn)
    for (name in removedNodes) {
      if (removedNodes.hasOwnProperty(name)) {
        updates = enqueue(
          updates,
          this._unmountChild(prevChildren[name], removedNodes[name])
        );
      }
    }
  }

三、基于Diff的開發(fā)建議

基于tree diff:

  • 開發(fā)組件時(shí),注意保持DOM結(jié)構(gòu)的穩(wěn)定;即,盡可能少地動(dòng)態(tài)操作DOM結(jié)構(gòu),尤其是移動(dòng)操作。
  • 當(dāng)節(jié)點(diǎn)數(shù)過大或者頁面更新次數(shù)過多時(shí),頁面卡頓的現(xiàn)象會(huì)比較明顯。
  • 這時(shí)可以通過 CSS 隱藏或顯示節(jié)點(diǎn),而不是真的移除或添加 DOM 節(jié)點(diǎn)。

基于component diff:

  • 注意使用 shouldComponentUpdate() 來減少組件不必要的更新。
  • 對于類似的結(jié)構(gòu)應(yīng)該盡量封裝成組件,既減少代碼量,又能減少component diff的性能消耗。

基于element diff:

  • 對于列表結(jié)構(gòu),盡量減少類似將最后一個(gè)節(jié)點(diǎn)移動(dòng)到列表首部的操作,當(dāng)節(jié)點(diǎn)數(shù)量過大或更新操作過于頻繁時(shí),在一定程度上會(huì)影響 React 的渲染性能。

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容! 

相關(guān)文章

  • 模塊化react-router配置方法詳解

    模塊化react-router配置方法詳解

    這篇文章主要介紹了模塊化react-router配置方法詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-06-06
  • React如何優(yōu)雅的捕獲異常

    React如何優(yōu)雅的捕獲異常

    捕獲異常是來定位你錯(cuò)誤代碼的。本文主要介紹了 React如何捕獲異常,你知道多少種方法,ErrorBoundary,ErrorBoundary-try-catch等等。本文就來詳細(xì)的介紹一下
    2021-06-06
  • react路由v6版本NavLink的兩個(gè)小坑及解決

    react路由v6版本NavLink的兩個(gè)小坑及解決

    這篇文章主要介紹了react路由v6版本NavLink的兩個(gè)小坑及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • 基于React實(shí)現(xiàn)倒計(jì)時(shí)功能

    基于React實(shí)現(xiàn)倒計(jì)時(shí)功能

    這篇文章主要為大家詳細(xì)介紹了如何基于React實(shí)現(xiàn)倒計(jì)時(shí)功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下
    2024-02-02
  • React 路由傳參的幾種實(shí)現(xiàn)方法

    React 路由傳參的幾種實(shí)現(xiàn)方法

    React中傳參方式有很多,通過路由傳參的方式也是必不可少的一種,本文主要介紹了React路由傳參的幾種實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-12-12
  • react中實(shí)現(xiàn)搜索結(jié)果中關(guān)鍵詞高亮顯示

    react中實(shí)現(xiàn)搜索結(jié)果中關(guān)鍵詞高亮顯示

    這篇文章主要介紹了react中實(shí)現(xiàn)搜索結(jié)果中關(guān)鍵詞高亮顯示,使用react實(shí)現(xiàn)要比js簡單很多,方法都是大同小異,具體實(shí)現(xiàn)代碼大家跟隨腳本之家小編一起看看吧
    2018-07-07
  • React移動(dòng)端項(xiàng)目之pdf預(yù)覽問題

    React移動(dòng)端項(xiàng)目之pdf預(yù)覽問題

    這篇文章主要介紹了React移動(dòng)端項(xiàng)目之pdf預(yù)覽問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • react hooks入門詳細(xì)教程

    react hooks入門詳細(xì)教程

    這篇文章主要介紹了react hooks入門詳細(xì)教程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • 詳解react中的state的簡寫方式

    詳解react中的state的簡寫方式

    React是一個(gè)狀態(tài)機(jī)主要體現(xiàn)在state上,通過與用戶交易實(shí)現(xiàn)不同的狀態(tài),state是組件的私有屬性,是用來初始化的,本文重點(diǎn)給大家介紹react中的state的簡寫方式,感興趣的朋友一起看看吧
    2021-08-08
  • 在react項(xiàng)目中webpack使用mock數(shù)據(jù)的操作方法

    在react項(xiàng)目中webpack使用mock數(shù)據(jù)的操作方法

    這篇文章主要介紹了在react項(xiàng)目中webpack使用mock數(shù)據(jù)的操作方法,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-06-06

最新評論

金寨县| 阆中市| 宁明县| 鄂伦春自治旗| 阳山县| 安顺市| 东源县| 武鸣县| 茂名市| 汾西县| 乌拉特后旗| 射阳县| 绥芬河市| 宣化县| 谢通门县| 万盛区| 平利县| 赞皇县| 南漳县| 中西区| 广元市| 潞西市| 延吉市| 彭州市| 务川| 上犹县| 洪雅县| 晋宁县| 柏乡县| 铁岭县| 万州区| 方城县| 沂南县| 蕉岭县| 乐至县| 西平县| 北宁市| 泰兴市| 宿迁市| 灵丘县| 天气|