成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

談?wù)凴eact中Diff算法的策略及實現(xiàn)

Scliang / 2629人閱讀

摘要:并且處理特殊屬性,比如事件綁定。之后根據(jù)差異對象操作元素位置變動,刪除,添加等。當(dāng)節(jié)點數(shù)過大或者頁面更新次數(shù)過多時,頁面卡頓的現(xiàn)象會比較明顯?;谧⒁馐褂脕頊p少組件不必要的更新。

1、什么是Diff算法

傳統(tǒng)Diff:diff算法即差異查找算法;對于Html DOM結(jié)構(gòu)即為tree的差異查找算法;而對于計算兩顆樹的差異時間復(fù)雜度為O(n^3),顯然成本太高,React不可能采用這種傳統(tǒng)算法;

React Diff:

之前說過,React采用虛擬DOM技術(shù)實現(xiàn)對真實DOM的映射,即React Diff算法的差異查找實質(zhì)是對兩個JavaScript對象的差異查找;

基于三個策略:

Web UI 中 DOM 節(jié)點跨層級的移動操作特別少,可以忽略不計。(tree diff)

擁有相同類的兩個組件將會生成相似的樹形結(jié)構(gòu),擁有不同類的兩個組件將會生成不同的樹形結(jié)(component diff)

對于同一層級的一組子節(jié)點,它們可以通過唯一 id 進行區(qū)分。(element diff)

2、React Diff算法解讀

首先需要明確,只有在React更新階段才會有Diff算法的運用;

React更新機制:

React Diff算法優(yōu)化策略圖:

React更新階段會對ReactElement類型判斷而進行不同的操作;ReactElement類型包含三種即:文本、Dom、組件;

每個類型的元素更新處理方式:

自定義元素的更新,主要是更新render出的節(jié)點,做甩手掌柜交給render出的節(jié)點的對應(yīng)component去管理更新。

text節(jié)點的更新很簡單,直接更新文案。

瀏覽器基本元素的更新,分為兩塊:

更新屬性,對比出前后屬性的不同,局部更新。并且處理特殊屬性,比如事件綁定。

子節(jié)點的更新,子節(jié)點更新主要是找出差異對象,找差異對象的時候也會使用上面的shouldUpdateReactComponent來判斷,如果是可以直接更新的就會遞歸調(diào)用子節(jié)點的更新,這樣也會遞歸查找差異對象。不可直接更新的刪除之前的對象或添加新的對象。之后根據(jù)差異對象操作dom元素(位置變動,刪除,添加等)。

事實上Diff算法只被調(diào)用于React更新階段的DOM元素更新過程;為什么這么說?

1、 如果為更新文本類型,內(nèi)容不同就直接更新替換,并不會調(diào)用復(fù)雜的Diff算法:

 ReactDOMTextComponent.prototype.receiveComponent(nextText, transaction) {
    //與之前保存的字符串比較
    if (nextText !== this._currentElement) {
      this._currentElement = nextText;
      var nextStringText = "" + nextText;
      if (nextStringText !== this._stringText) {
        this._stringText = nextStringText;
        var commentNodes = this.getHostNode();
        // 替換文本元素
        DOMChildrenOperations.replaceDelimitedText(
          commentNodes[0],
          commentNodes[1],
          nextStringText
        );
      }
    }
  }

2、對于自定義組件元素:

class Tab extends Component {
    constructor(props) {
        super(props);
        this.state = {
            index: 1,
        }
    }
    shouldComponentUpdate() {
        ....
    }
    render() {
        return (
            

item1

item1

) } }

需要明確的是,何為組件,可以說組件只不過是一段Html結(jié)構(gòu)的包裝容器,并且具備管理這段Html結(jié)構(gòu)的狀態(tài)等能力;

如上述Tab組件:它的實質(zhì)內(nèi)容就是render函數(shù)返回的Html結(jié)構(gòu),而我們所說的Tab類就是這段Html結(jié)構(gòu)的包裝容器(可以理解為一個包裝盒子);

在React渲染機制圖中可以看到,自定義組件的最后結(jié)合React Diff優(yōu)化策略一(不同類的兩個組件具備不同的結(jié)構(gòu))

3、基本元素:

ReactDOMComponent.prototype.receiveComponent = function(nextElement, transaction, context) {
    var prevElement = this._currentElement;
    this._currentElement = nextElement;
    this.updateComponent(transaction, prevElement, nextElement, context);
}

ReactDOMComponent.prototype.updateComponent = function(transaction, prevElement, nextElement, context) {
    //需要多帶帶的更新屬性
    this._updateDOMProperties(lastProps, nextProps, transaction, isCustomComponentTag);
    //再更新子節(jié)點
    this._updateDOMChildren(
      lastProps,
      nextProps,
      transaction,
      context
    );

    // ......
}

在this._updateDOMChildren方法內(nèi)部才調(diào)用了diff算法。

3、React中Diff算法的實現(xiàn)
_updateChildren: function(nextNestedChildrenElements, transaction, context) {
    var prevChildren = this._renderedChildren;
    var removedNodes = {};
    var mountImages = [];

    // 獲取新的子元素數(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) {
        // 同一個引用,說明是使用的同一個component,所以我們需要做移動的操作
        // 移動已有的子節(jié)點
        // NOTICE:這里根據(jù)nextIndex, lastIndex決定是否移動
        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é)點在指定的位置上
        updates = enqueue(
          updates,
          this._mountChildAtIndex(
            nextChild,
            mountImages[nextMountIndex],
            lastPlacedNode,
            nextIndex,
            transaction,
            context
          )
        );


        nextMountIndex++;
      }

      // 更新nextIndex
      nextIndex++;
      lastPlacedNode = ReactReconciler.getHostNode(nextChild);
    }

    // 移除掉不存在的舊子節(jié)點,和舊子節(jié)點和新子節(jié)點不同的舊子節(jié)點
    for (name in removedNodes) {
      if (removedNodes.hasOwnProperty(name)) {
        updates = enqueue(
          updates,
          this._unmountChild(prevChildren[name], removedNodes[name])
        );
      }
    }
  }
5、基于中Diff的開發(fā)建議

基于tree diff:

開發(fā)組件時,注意保持DOM結(jié)構(gòu)的穩(wěn)定;即,盡可能少地動態(tài)操作DOM結(jié)構(gòu),尤其是移動操作。

當(dāng)節(jié)點數(shù)過大或者頁面更新次數(shù)過多時,頁面卡頓的現(xiàn)象會比較明顯。

這時可以通過 CSS 隱藏或顯示節(jié)點,而不是真的移除或添加 DOM 節(jié)點。

基于component diff

注意使用 shouldComponentUpdate() 來減少組件不必要的更新。

對于類似的結(jié)構(gòu)應(yīng)該盡量封裝成組件,既減少代碼量,又能減少component diff的性能消耗。

基于element diff

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

接下來手動實現(xiàn)一個簡單的Diff算法即將更新,敬請期待~~~

“積跬步、行千里”—— 持續(xù)更新中~,喜歡留下個贊哦!

往期經(jīng)典好文:

團隊合作必備的Git操作

談?wù)凧s前端規(guī)范化

從React渲染流程分析Diff算法

相關(guān)專欄推薦:

React學(xué)習(xí)之路

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/98014.html

相關(guān)文章

  • 談?wù)?/em>ReactDiff算法策略實現(xiàn)

    摘要:并且處理特殊屬性,比如事件綁定。之后根據(jù)差異對象操作元素位置變動,刪除,添加等。當(dāng)節(jié)點數(shù)過大或者頁面更新次數(shù)過多時,頁面卡頓的現(xiàn)象會比較明顯?;谧⒁馐褂脕頊p少組件不必要的更新。 1、什么是Diff算法 傳統(tǒng)Diff:diff算法即差異查找算法;對于Html DOM結(jié)構(gòu)即為tree的差異查找算法;而對于計算兩顆樹的差異時間復(fù)雜度為O(n^3),顯然成本太高,React不可能采用這種...

    HmyBmny 評論0 收藏0
  • react diff算法

    摘要:算法的本質(zhì)是對傳統(tǒng)遍歷算法的優(yōu)化策略用三大策略將復(fù)雜度轉(zhuǎn)化為復(fù)雜度策略一中節(jié)點跨層級的移動操作特別少,可以忽略不計。當(dāng)節(jié)點處于同一層級時,提供三種節(jié)點操作刪除插入移動。在舊的節(jié)點中的,它的,不滿足的條件,因此不做移動操作。 一、react diff算法 diff算法的作用 計算出Virtual DOM中真正變化的部分,并只針對該部分進行原生DOM操作,而非重新渲染整個頁面。 傳統(tǒng)di...

    imccl 評論0 收藏0
  • react基本原理性能優(yōu)化

    摘要:對同一層級的子節(jié)點進行處理時,會根據(jù)進行簡要的復(fù)用。二性能優(yōu)化方案由于中性能主要耗費在于階段的算法,因此性能優(yōu)化也主要針對算法。此時最常用的優(yōu)化方案即為方法?;蛘咧苯邮褂?,原理一致。 一、從React原理談起 react是什么? showImg(https://segmentfault.com/img/bVbcYvf?w=1140&h=384); react是用于構(gòu)建用戶界面的JS框架...

    VincentFF 評論0 收藏0
  • react基本原理性能優(yōu)化

    摘要:對同一層級的子節(jié)點進行處理時,會根據(jù)進行簡要的復(fù)用?;蛘咧苯邮褂茫硪恢?。 一、從React原理談起 react是什么? showImg(https://segmentfault.com/img/bVbcYvf?w=1140&h=384); react是用于構(gòu)建用戶界面的JS框架。因此react只負(fù)責(zé)解決view層的渲染。 react做了什么? Virtual Dom模型 生命周期...

    pinecone 評論0 收藏0

發(fā)表評論

0條評論

Scliang

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<