国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

React diff算法

caozhijian / 685人閱讀

摘要:傳統(tǒng)算法通過循環(huán)遞歸對節(jié)點進行依次對比,效率低下,算法復雜度達到,其中是樹中節(jié)點的總數(shù)。對于同一層級的一組子節(jié)點,它們可以通過唯一進行區(qū)分。當發(fā)現(xiàn)節(jié)點已經(jīng)不存在,則該節(jié)點及其子節(jié)點會被完全刪除掉,不會用于進一步的比較。

https://zhuanlan.zhihu.com/p/...

React diff 會幫助我們計算出 Virtual DOM 中真正變化的部分,并只針對該部分進行實際 DOM 操作,而非重新渲染整個頁面,從而保證了每次操作更新后頁面的高效渲染,因此 Virtual DOM 與 diff 是保證 React 性能口碑的幕后推手。

計算一棵樹形結(jié)構(gòu)轉(zhuǎn)換成另一棵樹形結(jié)構(gòu)的最少操作,是一個復雜且值得研究的問題。傳統(tǒng) diff 算法通過循環(huán)遞歸對節(jié)點進行依次對比,效率低下,算法復雜度達到 O(n3),其中 n 是樹中節(jié)點的總數(shù)。

diff 策略

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

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

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

tree diff 通過分層求異的策略

對樹進行分層比較,兩棵樹只會對同一層次的節(jié)點進行比較。既然 DOM 節(jié)點跨層級的移動操作少到可以忽略不計,針對這一現(xiàn)象,React 通過 updateDepth 對 Virtual DOM 樹進行層級控制,只會對相同顏色方框內(nèi)的 DOM 節(jié)點進行比較,即同一個父節(jié)點下的所有子節(jié)點。當發(fā)現(xiàn)節(jié)點已經(jīng)不存在,則該節(jié)點及其子節(jié)點會被完全刪除掉,不會用于進一步的比較。這樣只需要對樹進行一次遍歷,便能完成整個 DOM 樹的比較。

由于 React 只會簡單的考慮同層級節(jié)點的位置變換,而對于不同層級的節(jié)點,只有創(chuàng)建和刪除操作。當出現(xiàn)節(jié)點跨層級移動時,并不會出現(xiàn)想象中的移動操作,而是以 A 為根節(jié)點的樹被整個重新創(chuàng)建,這是一種影響 React 性能的操作,因此 React 官方建議不要進行 DOM 節(jié)點跨層級的操作。

component diff 通過相同類生成相似樹形結(jié)構(gòu),不同類生成不同樹形結(jié)構(gòu)的策略

React 是基于組件構(gòu)建應(yīng)用的,對于組件間的比較所采取的策略也是簡潔高效。

如果是同一類型的組件,按照原策略繼續(xù)比較 virtual DOM tree。

如果不是,則將該組件判斷為 dirty component,從而替換整個組件下的所有子節(jié)點。

對于同一類型的組件,有可能其 Virtual DOM 沒有任何變化,如果能夠確切的知道這點那可以節(jié)省大量的 diff 運算時間,因此 React 允許用戶通過 shouldComponentUpdate() 來判斷該組件是否需要進行 diff。

如下圖,當 component D 改變?yōu)?component G 時,即使這兩個 component 結(jié)構(gòu)相似,一旦 React 判斷 D 和 G 是不同類型的組件,就不會比較二者的結(jié)構(gòu),而是直接刪除 component D,重新創(chuàng)建 component G 以及其子節(jié)點。

element diff 通過設(shè)置唯一 key的策略

當節(jié)點處于同一層級時,React diff 提供了三種節(jié)點操作,分別為:INSERT_MARKUP(插入)、MOVE_EXISTING(移動)和 REMOVE_NODE(刪除)。

INSERT_MARKUP,新的 component 類型不在老集合里, 即是全新的節(jié)點,需要對新節(jié)點執(zhí)行插入操作。

MOVE_EXISTING,在老集合有新 component 類型,且 element 是可更新的類型,generateComponentChildren 已調(diào)用 receiveComponent,這種情況下 prevChild=nextChild,就需要做移動操作,可以復用以前的 DOM 節(jié)點。

REMOVE_NODE,老 component 類型,在新集合里也有,但對應(yīng)的 element 不同則不能直接復用和更新,需要執(zhí)行刪除操作,或者老 component 不在新集合里的,也需要執(zhí)行刪除操作。

允許開發(fā)者對同一層級的同組子節(jié)點,添加唯一 key 進行區(qū)分,雖然只是小小的改動,性能上卻發(fā)生了翻天覆地的變化!

先對新集合的節(jié)點進行循環(huán)遍歷,for (name in nextChildren),通過唯一 key 可以判斷新老集合中是否存在相同的節(jié)點,if (prevChild === nextChild),如果存在相同節(jié)點,則進行移動操作,但在移動前需要將當前節(jié)點在老集合中的位置與 lastIndex 進行比較,if (child._mountIndex < lastIndex),則進行節(jié)點移動操作,否則不執(zhí)行該操作。==這是一種順序優(yōu)化手段,lastIndex 一直在更新,表示訪問過的節(jié)點在老集合中最右的位置(即最大的位置)==,如果新集合中當前訪問的節(jié)點比 lastIndex 大,說明當前訪問節(jié)點在老集合中就比上一個節(jié)點位置靠后,則該節(jié)點不會影響其他節(jié)點的位置,因此不用添加到差異隊列中,即不執(zhí)行移動操作,只有當訪問的節(jié)點比 lastIndex 小時,才需要進行移動操作。

總結(jié)

React 通過制定大膽的 diff 策略,將 O(n3) 復雜度的問題轉(zhuǎn)換成 O(n) 復雜度的問題;

React 通過分層求異的策略,對 tree diff 進行算法優(yōu)化;

React 通過相同類生成相似樹形結(jié)構(gòu),不同類生成不同樹形結(jié)構(gòu)的策略,對 component diff 進行算法優(yōu)化;

React 通過設(shè)置唯一 key的策略,對 element diff 進行算法優(yōu)化;

建議,在開發(fā)組件時,保持穩(wěn)定的 DOM 結(jié)構(gòu)會有助于性能的提升;

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

Diff Algorithm

Level by Level

List

Components

Event Delegation Rendering

Batching

Sub-tree Rendering

Selective Sub-tree Rendering

diff策略

oldVdom不存在時,將newVdom生成的dom添加到父元素
newVdom不存在時,將newVdom對應(yīng)index的真實dom刪除
oldVdom, newVdom 的根節(jié)點不一致時,直接將oldVdom替換為newVdom
若上述都不滿足,則說明兩個vdom的根節(jié)點是一致的, 然后遞歸調(diào)用 diff & patch 方法

function h(type, props, ...children) {
    return {type, props, children};
}

function createElement(node) {
    if (typeof node === "string") {
        return document.createTextNode(node);
    }
    const $el = document.createElement(node.type);
    node.children
        .map(createElement)
        .forEach($el.appendChild.bind($el));
    return $el;
}

function changed(node1, node2) {
    return typeof node1 !== typeof node2 ||
        typeof node1 === "string" && node1 !== node2 ||
        node1.type !== node2.type
}

function updateElement($parent, newNode, oldNode, index = 0) {
    console.log(Array.from(arguments))
    // console.log(newNode)
    // console.log(newNode)

    if (!oldNode) {
        $parent.appendChild(
            createElement(newNode)
        );
    } else if (!newNode) {
        $parent.removeChild(
            $parent.childNodes[index]
        );
    } else if (changed(newNode, oldNode)) {
        console.log("if go changed")
        console.log(newNode, oldNode)
        $parent.replaceChild(
            createElement(newNode),
            $parent.childNodes[index]
        );
    } else if (newNode.type) {
        console.log("test if go last if")
        const newLength = newNode.children.length;
        const oldLength = oldNode.children.length;
        for (let i = 0; i < newLength || i < oldLength; i++) {
            updateElement(
                $parent.childNodes[index],
                newNode.children[i],
                oldNode.children[i],
                i
            );
        }
    }
}

// ---------------------------------------------------------------------

// let a = (
//     
    //
  • item 1
  • //
  • item 2
  • //
// ); // // let b = ( //
    //
  • item 1
  • //
  • hello!
  • //
// ); let a = h("ul", {}, h("li", {}, "item1"), h("li", {}, "item2")) let b = h("ul", {}, h("li", {}, "item1"), h("li", {}, "hello!")) const $root = document.getElementById("root"); const $reload = document.getElementById("reload"); updateElement($root, a); $reload.addEventListener("click", () => { updateElement($root, b, a); }); // 4. vdom diffs && patch //index Virtual DOM對應(yīng)處于真實DOM中的第幾個子節(jié)點 function btsPatch(parentDomNode, oldVdom, newVdom, index=0) { if(!oldVdom) parentDomNode.appendChild(applyVDom(newVdom)); if(!newVdom) { if(parentDomNode.childNodes) parentDomNode.removeChild(parentDomNode.childNodes[index]); } if(typeof oldVdom != typeof newVdom || (typeof oldVdom == "string" && oldVdom != newVdom) || (typeof oldVdom == "object" && oldVdom.name != newVdom.name) ) { if(parentDomNode.childNodes && parentDomNode.childNodes[index]) parentDomNode.removeChild(parentDomNode.childNodes[index]); parentDomNode.appendChild(applyVDom(newVdom)); } else { if( typeof oldVdom == "object" ) { let count = Math.max(oldVdom.children.length, newVdom.children.length); if(count > 0) { for(let i=0; i < count; i++) { btsPatch(parentDomNode.childNodes[index], oldVdom.children[i], newVdom.children[i], i); } } } } return // done bts or same string or no children }

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

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

相關(guān)文章

  • 談?wù)?em>React中Diff算法的策略及實現(xiàn)

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

    Scliang 評論0 收藏0
  • 談?wù)?em>React中Diff算法的策略及實現(xiàn)

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

    HmyBmny 評論0 收藏0
  • React diff原理探究以及應(yīng)用實踐

    摘要:但是加了一定要比沒加的性能更高嗎我們再來看一個例子現(xiàn)在有一集合渲染成如下的樣子現(xiàn)在我們將這個集合的順序打亂變成。不加操作修改第個到第個節(jié)點的如果我們對這個集合進行增刪的操作改成。 拋磚引玉 React通過引入Virtual DOM的概念,極大地避免無效的Dom操作,已使我們的頁面的構(gòu)建效率提到了極大的提升。但是如何高效地通過對比新舊Virtual DOM來找出真正的Dom變化之處同樣也...

    EasonTyler 評論0 收藏0
  • react虛擬dom機制與diff算法

    摘要:的一個突出特點是擁有極速地渲染性能。該功能依靠的就是研發(fā)團隊弄出的虛擬機制以及其獨特的算法。在的算法下,在同一位置對比前后節(jié)點只要發(fā)現(xiàn)不同,就會刪除操作前的節(jié)點包括其子節(jié)點,替換為操作后的節(jié)點。 React的一個突出特點是擁有極速地渲染性能。該功能依靠的就是facebook研發(fā)團隊弄出的虛擬dom機制以及其獨特的diff算法。下面簡單解釋一下react虛擬dom機制和diff算法的實現(xiàn)...

    jzman 評論0 收藏0
  • React 源碼剖析系列 - 不可思議的 react diff

    摘要:目前,前端領(lǐng)域中勢頭正盛,使用者眾多卻少有能夠深入剖析內(nèi)部實現(xiàn)機制和原理。當發(fā)現(xiàn)節(jié)點已經(jīng)不存在,則該節(jié)點及其子節(jié)點會被完全刪除掉,不會用于進一步的比較。 目前,前端領(lǐng)域中 React 勢頭正盛,使用者眾多卻少有能夠深入剖析內(nèi)部實現(xiàn)機制和原理。本系列文章希望通過剖析 React 源碼,理解其內(nèi)部的實現(xiàn)原理,知其然更要知其所以然。 React diff 作為 Virtual DOM 的加速...

    shuibo 評論0 收藏0

發(fā)表評論

0條評論

caozhijian

|高級講師

TA的文章

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