浅谈从React渲染流程分析Diff算法

前端之家收集整理的这篇文章主要介绍了浅谈从React渲染流程分析Diff算法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

React中最神奇的部分莫过于虚拟DOM,以及其高效的Diff算法。这让我们可以无需担心性能问题而”毫无顾忌”的随时“刷新”整个页面,由虚拟DOM来确保只对界面上真正变化的部分进行实际的DOM操作。React在这一部分已经做到足够透明,在实际开发中我们基本无需关心虚拟DOM是如何运作的。然而,理解其运行机制不仅有助于更好的理解React组件的生命周期,而且对于进一步优化React程序也会有很大帮助。

1、什么是虚拟DOM

在React中,render执行的结果得到的并不是真正的DOM节点,结果仅仅是轻量级的JavaScript对象,我们称之为virtual DOM。

简单的说,其实所谓的virtual DOM就是JavaScript对象到Html DOM节点的映射;即使用JavaScript对象将Html结构表示出来,而这个对象就是virtual DOM。

eg:

Html:

  • Item 1
  • Item 2
  • JavaScript对象表示(virtual DOM)

    2、什么时候会生成到virtual DOM

    React生命周期拥有装载、更新、卸载的三个阶段;附上一张React生命周期图

    前面提到:render执行的结果得到的并不是真正的DOM节点,结果仅仅是轻量级的JavaScript对象,即在render函数调用时将会创建出虚拟DOM;

    通过React.createElemen创建出虚拟DOM,而该函数只在Render函数调用,所以在React装载和更新的过程中才会有虚拟DOM的生成;至于挂载到真实DOM自然而然是ReactDom.render函数啦。

    3、virtual DOM如何实现

    实现其实很简单,主要是定义一个函数并把我们传进去的参数组成一个React元素对象,而type就是我们传进去的组件类型,可以是一个类、函数或字符串(如'div')

    React大致源码:

    const props = {};

    let key = null;
    let ref = null;
    let self = null;
    let source = null;

    if (config != null) {
    if (hasValidRef(config)) {
    // 如果有ref,将它取出来
    ref = config.ref;
    }
    if (hasValidKey(config)) {
    // 如果有key,将它取出来
    key = '' + config.key;
    }

    self = config.self === undefined ? null : config.self;
    source = config.source === undefined ? null : config.source;

    for (propName in config) {
    if (
    hasOwnProperty.call(config,propName) &&
    !RESERVED_PROPS.hasOwnProperty(propName)
    ) {
    // 将除ref,key等这些特殊的属性放到新的props对象里
    props[propName] = config[propName];
    }
    }
    }

    // 获取子元素
    const childrenLength = arguments.length - 2;
    if (childrenLength === 1) {
    props.children = children;
    } else if (childrenLength > 1) {
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
    childArray[i] = arguments[i + 2];
    }
    props.children = childArray;
    }

    // 添加默认props
    if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
    if (props[propName] === undefined) {
    props[propName] = defaultProps[propName];
    }
    }
    }

    return ReactElement(
    type,key,ref,self,source,ReactCurrentOwner.current,props,);
    }

    const ReactElement = function(type,owner,props) {
    // 最终得到的React元素
    const element = {
    // This tag allows us to uniquely identify this as a React Element
    $$typeof: REACT_ELEMENT_TYPE,// Built-in properties that belong on the element
    type: type,key: key,ref: ref,props: props,// Record the component responsible for creating this element.
    _owner: owner,};

    return element;
    };

    打印出组件:

    4、为什么需要使用virtual DOM

    DOM管理历史阶段:

    1. JS 或者 jQuery 操作 DOM: 当应用程序越来越复杂,需要在JS里面维护的字段也越来越多,需要监听事件和在事件回调用更新页面的DOM操作也越来越多,应用程序会变得非常难维护。
    2. 后来产出 MVC、MVP 的架构模式,期望从代码组织方式来降低维护难度。但是 MVC 架构并没办法减少维护的状态,也没有降低状态更新时需要对页面的更新操作,你需要操作的DOM还是需要操作,只是换了个地方。
    3. 既然状态改变了要操作相应的DOM元素,为什么不做一个东西让视图和状态进行绑定,状态变更了视图自动变更。这就是后来人们想出了 MVVM 模式,只要在模版中声明视图组件是和什么状态进行绑定的,双向绑定引擎就会在状态更新的时候自动更新视图;
    4. 但MVVM双向数据绑定并不是唯一的办法,还有一个非常直观的方法:一旦状态发生了变化,就用模版引擎重新渲染整个视图,然后用新的视图更换掉旧的视图。

    React采用的就是第四种模式;但是我们都知道对于操作DOM成本太高,而相对操作JavaScript就快速多了,而Html DOM可以很简单的用JavaScript对象表示出来(Virtual DOM就这样诞生了)

    这样的做法会导致很多的问题,最大的问题就是这样做会很慢,因为即使一个小小的状态变更都要重新构造整棵 DOM,性价比太低;而React Virtual DOM在状态更新过程加了一些特别的操作来避免整棵 DOM 树变更(它就是接下来的Diff算法)。

    接下来的Diff算法即将更新,敬请期待~~~

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。

    猜你在找的JavaScript相关文章