一、什么是虚拟DOM
在React中,render执行的结果获得的并非真正的DOM节点,结果仅仅是轻量级的JavaScript对象,咱们称之为virtual DOM。
- 简单的说,其实所谓的virtual DOM就是JavaScript对象到Html DOM节点的映射;即便用JavaScript对象将Html结构表示出来,而这个对象就是virtual DOM。
- eg:
- Html:
<ul id='list'> <li class='item'>Item 1</li> <li class='item'>Item 2</li> </ul>
- JavaScript对象表示(virtual DOM)
{ tagName: 'ul', props: { id: 'list' }, children: [ {tagName: 'li', props: {class: 'item'}, children: ["Item 1"]}, {tagName: 'li', props: {class: 'item'}, children: ["Item 2"]}, ] }
二、何时会生成到virtual DOM
- React生命周期拥有装载、更新、卸载的三个阶段;附上一张React生命周期图
- 前面提到:render执行的结果获得的并非真正的DOM节点,结果仅仅是轻量级的JavaScript对象,即在render函数调用时将会建立出虚拟DOM;
class Tab extends React.Component { render() { React.createElement( 'p', { className: 'class'}, 'Hello React' ) } }
- 经过React.createElemen建立出虚拟DOM,而该函数只在Render函数中调用,因此在React装载和更新的过程当中才会有虚拟DOM的生成;至于挂载到真实DOM天然而然是ReactDom.render函数啦。
三、virtual DOM如何实现
- 实现其实很简单,主要是定义一个函数并把咱们传进去的参数组成一个React元素对象,而type就是咱们传进去的组件类型,能够是一个类、函数或字符串(如'div')
- React大体源码:
function createElement(type, config, children) { let propName; 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, key, ref, self, source, 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; };
- 打印出组件:
四、为何须要使用virtual DOM
-
DOM管理历史阶段:前端
- JS 或者 jQuery 操做 DOM: 当应用程序愈来愈复杂,须要在JS里面维护的字段也愈来愈多,须要监听事件和在事件回调用更新页面的DOM操做也愈来愈多,应用程序会变得很是难维护。
- 后来产出 MVC、MVP 的架构模式,指望从代码组织方式来下降维护难度。可是 MVC 架构并没办法减小维护的状态,也没有下降状态更新时须要对页面的更新操做,你须要操做的DOM仍是须要操做,只是换了个地方。
- 既然状态改变了要操做相应的DOM元素,为何不作一个东西让视图和状态进行绑定,状态变动了视图自动变动。这就是后来人们想出了 MVVM 模式,只要在模版中声明视图组件是和什么状态进行绑定的,双向绑定引擎就会在状态更新的时候自动更新视图;
- 但MVVM双向数据绑定并非惟一的办法,还有一个很是直观的方法:一旦状态发生了变化,就用模版引擎从新渲染整个视图,而后用新的视图更换掉旧的视图。
- React采用的就是第四种模式;可是咱们都知道对于操做DOM成本过高,而相对操做JavaScript就快速多了,而Html DOM能够很简单的用JavaScript对象表示出来(Virtual DOM就这样诞生了)
- 这样的作法会致使不少的问题,最大的问题就是这样作会很慢,由于即便一个小小的状态变动都要从新构造整棵 DOM,性价比过低;而React Virtual DOM在状态更新过程加了一些特别的操做来避免整棵 DOM 树变动(它就是接下来的Diff算法)。
- 接下来的Diff算法即将更新,敬请期待~~~
“积跬步、行千里”—— 持续更新中~,喜欢留下个赞哦!
-
往期经典好文:算法
-
相关专栏推荐:segmentfault