美文网首页
React-Diff算法

React-Diff算法

作者: zhulichao | 来源:发表于2020-08-26 09:22 被阅读0次

Diff算法

React.js 相对于直接操作原生DOM有很大的性能优势,很大程度上都要归功于virtual DOM的batching和diff。batching把所有的DOM操作搜集起来,一次性提交给真实的DOM。diff算法时间复杂度也从标准的的Diff算法的O(n3)降到了O(n)。React.js将标准的的Diff算法复杂度O(n3)直接降低到O(n)基于的假设:

  • 两个相同组件产生类似的DOM结构,不同的组件产生不同的DOM结构
  • 对于同一层次的一组子节点,它们可以通过唯一的id进行区分

在比较两个React节点树时,React首先比较根元素,随后的行为取决于根元素类型:

  • 只要根节点类型不同,React就会销毁旧节点树,创建新节点树
  • 当节点类型相同时,React比较两者的属性,不改变DOM节点,只更新当前节点需要改变的属性
  • 如果节点需要更新样式属性,React仅会更新当前节点需要改变的样式属性

React的Diff算法实际上只会对树进行逐层比较。在实现自己的组件时,保持稳定的DOM结构会有助于性能的提升。例如,我们有时可以通过CSS隐藏或显示某些节点,而不是真的移除或添加DOM节点。

传统算法O(n^3)(转) React算法O(n)(转)

key属性在diff算法中的作用

使用浏览器的MutationObserver的功能,对页面上元素的改变进行监听,示例代码如下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script src="react.js"></script>
    <script src="react-dom.js"></script>
    <script src="jquery.js"></script>
    <script src="babel.min.js"></script>
  </head>
  <body>
    <div id="container"></div>
    <style>

    </style>
    <script type="text/javascript">
        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
        var observeMutationSupport = !!MutationObserver;
        var changedNodes = [];
        if(observeMutationSupport) {
            var observer = new MutationObserver(function(mutations) {
                changedNodes = mutations;
                mutations.forEach(function(mutation){
                    console.log(mutation);
                });
            });
            var options = {
                'childList': true, // 子节点的变动
                'attributes': true, // 属性的变动
                'characterData': true, // 节点内容或节点文本的变动
                'subtree': true, // 所有后代节点的变动
                'attributeOldValue': true, // 表示观察attributes变动时,是否需要记录变动前的属性值
                'characterDataOldValue': true // 表示观察characterData变动时,是否需要记录变动前的值
            };
            observer.observe(document.body, options);
        }
    </script>
    <script type="text/babel">
        function LifeCycle(name) {
            var obj = {
                name: name
            };
            for(var n in Cycle){
                obj[n] = Cycle[n];
            }
            return obj;
        }
        var Cycle = {
            getInitialState: function() {
                console.log(this.name, 'getInitialState');
                return {};
            },
            getDefaultProps: function() {
                console.log(this.name, 'getDefaultProps');
                return {};
            },
            componentWillMount: function() {
                console.log(this.name, 'componentWillMount');
            },
            componentDidMount: function() {
                console.log(this.name, 'componentDidMount');
            },
            componentWillReceiveProps: function() {
                console.log(this.name, 'componentWillReceiveProps');
            },
            shouldComponentUpdate: function() {
                console.log(this.name, 'shouldComponentUpdate');
                return true;
            },
            componentWillUpdate: function() {
                console.log(this.name, 'componentWillUpdate');
            },
            componentDidUpdate: function() {
                console.log(this.name, 'componentDidUpdate');
            },
            componentWillUnmount: function() {
                console.log(this.name, 'componentWillUnmount');
            }
        };
        // 定义Ctrip组件
        var Ctrip = React.createClass({
            mixins: [LifeCycle('Ctrip')],
            render: function() {
                console.log('Ctrip', 'render');
                return (
                    <ul>
                        <li>ctrip</li>
                        <li>
                            <ul>
                                {this.props.children}
                            </ul>
                        </li>
                    </ul>
                );
            }
        });
        // 定义Elong组件
        var Elong = React.createClass({
            mixins: [LifeCycle('Elong')],
            render: function() {
                console.log('Elong', 'render');
                return (
                    <li>elong</li>
                );
            }
        });
        // 定义Qunar组件
        var Qunar = React.createClass({
            mixins: [LifeCycle('Qunar')],
            render: function() {
                console.log('Qunar', 'render');
                return (
                    <li>qunar</li>
                );
            }
        });
        // 定义Ly组件
        var Ly = React.createClass({
            mixins: [LifeCycle('Ly')],
            render: function () {
                console.log('Ly', 'render');
                return (
                    <li>ly</li>
                );
            }
        });

        console.log('------------first------------');
        ReactDOM.render(
            <Ctrip><Elong></Elong><Qunar></Qunar></Ctrip>,
            document.getElementById('container')
        );
        setTimeout(function() {
            console.log('------------second------------');
            ReactDOM.render(
                <Ctrip><Elong></Elong><Ly></Ly><Qunar></Qunar></Ctrip>,
                document.getElementById('container')
            );
        }, 1000);
    </script>
  </body>
</html>

运行结果如图

常规的做法就是将Elong和Qunar组件先删除,然后一次创建和插入Elong、Ly和Qunar组件。通过运行结果可以看出,在React中,Elong组件不变,先将Qunar组件进行删除,然后在创建并插入Ly组件,最后再创建并插入Qunar组件,比常规的做法省去了对Elong组件的删除操作。下面再将主逻辑代码稍作调整,给每个组件添加key属性:

...
console.log('------------first------------');
ReactDOM.render(
    <Ctrip><Elong key="Elong"></Elong><Qunar key="Qunar"></Qunar></Ctrip>,
    document.getElementById('container')
);
setTimeout(function() {
    console.log('------------second------------');
    ReactDOM.render(
        <Ctrip><Elong key="Elong"></Elong><Ly key="Ly"></Ly><Qunar key="Qunar"></Qunar></Ctrip>,
        document.getElementById('container')
    );
}, 1000);
...
运行结果如图

这次的Diff算法与之前有很大不同,Elong组件不变,Qunar组件不变,只是在Qunar组件之前创建并插入了Ly组件。可见使用key属性可提高渲染性能。

相关文章

  • React-Diff算法

    Diff算法 React.js 相对于直接操作原生DOM有很大的性能优势,很大程度上都要归功于virtual DO...

  • react进阶-节点比较

    1.key增加性能,需要注意: 2.关于key的使用 3.diff算法 react-diff算法就是上面说的启发式...

  • react-diff算法详解

    前言 本文是我阅读《深入React技术栈》所写的总结笔记。如果您觉得本站的markdown代码高亮不友好,建议您查...

  • React-diff

    React是根据Virtual DOM的对比来更新DOM的。这种用来对比的方法被称为diff算法,该算法由fb进一...

  • 匈牙利算法

    算法思想 算法流程 算法步骤 算法实现 python 算法应用

  • web开发需要知道的几个算法

    算法分类 快速排序算法 深度优先算法 广度优先算法 堆排序算法 归并排序算法

  • 机器学习算法

    机器学习的算法分监督算法和无监督 算法。监督算法包括回归算法,神经网络,SVM;无监督算法包括聚类算法,降维算法。...

  • 字符串匹配

    BF 算法和 RK 算法BM 算法和 KMP 算法

  • 垃圾回收算法有几种类型? 他们对应的优缺点又是什么?

    常见的垃圾回收算法有: 标记-清除算法、复制算法、标记-整理算法、分代收集算法 标记-清除算法 标记—清除算法包括...

  • 头条-手撕代码

    [toc] 图算法 以及最短路径算法 树算法 手写LRU 排序算法 链表算法

网友评论

      本文标题:React-Diff算法

      本文链接:https://www.haomeiwen.com/subject/mradhktx.html