摘要:对回收的处理在中,回收调用了两个方法,节点的回收一般会调用,组件的回收会调用。个人理解从以上源码阅读中我们可以看到,最大的性能问题在于递归的,中的与也是为了缓解这个问题。为不同类型的更新分配优先级。
对回收的处理
在preact中,回收调用了两个方法,dom节点的回收一般会调用recollectNodeTree,组件的回收会调用unmountComponent。
preact复用dom的秘密在于当要卸载一个组件的时候,只有组件的根节点会从父节点上卸载掉,组件完整的dom仍然存在,被卸载的组件会保存在components对象中。
在创建组件的时候又通过nodeName拿到对应的dom节点树,挂载在组件实例的inst.nextBase上,在renderComponent的时候,再diff nextBase与新的虚拟dom树rendered。
相关主要代码如下:
function createComponent(Ctor, props, context) { let list = components[Ctor.name], inst; if (Ctor.prototype && Ctor.prototype.render) { inst = new Ctor(props, context); Component.call(inst, props, context); } else { // 对应函数组件 inst = new Component(props, context); inst.constructor = Ctor; inst.render = doRender; } if (list) { for (let i = list.length; i--;) { if (list[i].constructor === Ctor) { inst.nextBase = list[i].nextBase; list.splice(i, 1); break; } } } return inst; }setState的处理
更改组件上的state,然后将要渲染的组件放在一个数组中,在下一次event loop的时候渲染:
setState: function setState(state, callback) { let s = this.state; if (!this.prevState) this.prevState = extend({}, s); extend(s, typeof state === "function" ? state(s, this.props) : state); if (callback)(this._renderCallbacks = this._renderCallbacks || []).push(callback); enqueueRender(this); }, function enqueueRender(component) { // component._dirty为false且items原本为空数组就能渲染 if (!component._dirty && (component._dirty = true) && items.push(component) == 1) { (options.debounceRendering || defer)(rerender); //异步的执行render,要执行render方法的component中的_dirty设为true } }, function rerender() { let p, list = items; items = []; while (p = list.pop()) { if (p._dirty) renderComponent(p); } }preact对事件的处理
preact为了减少增减事件对性能和内存的影响,当为dom做事件监听时,添加的是一个代理函数。
function setAccessor(node, name, old, value, isSvg) { // ... if (name[0] == "o" && name[1] == "n") { let useCapture = name !== (name = name.replace(/Capture$/, "")); name = name.toLowerCase().substring(2); if (value) { if (!old) node.addEventListener(name, eventProxy, useCapture); } else { node.removeEventListener(name, eventProxy, useCapture); } (node._listeners || (node._listeners = {}))[name] = value; } // ... }
function eventProxy(e) { return this._listeners[e.type](options.event && options.event(e) || e); }fiber(个人理解)
从以上源码阅读中我们可以看到,react最大的性能问题在于递归的diff,react中的shouldCompnentUpdate与PureComponent也是为了缓解这个问题。但是当应用比较大的时候一个高级别组件的diff还是很容易使得动画掉帧。
fiber的出现就是为了解决这个问题,react fiber将计算工作分成了多个小片,这使得整个计算工作可以暂停,中止,或重新开始。为不同类型的更新分配优先级。当动画或用户交互触发时,就可以先暂停低优先级的更新工作,保证动画的流畅性,等所有的渲染计算工作完成,对dom更新进行一次commit。
参考https://calendar.perfplanet.c...
https://reactjs.org/docs/impl...
https://segmentfault.com/a/11...
https://www.w3ctech.com/topic...
https://zhuanlan.zhihu.com/p/...
https://github.com/acdlite/re...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/95133.html
摘要:是一个最小的库,但由于其对尺寸的追求,它的很多代码可读性比较差,市面上也很少有全面且详细介绍的文章,本篇文章希望能帮助你学习的源码。建议与源码一起阅读本文。 作为一名前端,我们需要深入学习react的运行机制,但是react源码量已经相当庞大,从学习的角度,性价比不高,所以学习一个react mini库是一个深入学习react的一个不错的方法。 preact是一个最小的react mi...
摘要:最后删除新的树中不存在的节点。而中会记录对其做了相应的优化,节点的的情况下,不做移动操作。这种情况,在中得到了优化,通过四个指针,在每次循环中先处理特殊情况,并通过缩小指针范围,获得性能上的提升。 上篇文章已经介绍过idff的处理逻辑主要分为三块,处理textNode,element及component,但具体怎么处理component还没有详细介绍,接下来讲一下preact是如何处理...
摘要:基本介绍选择式排序也属于内部排序法,是从欲排序的数据中,按指定的规则选出某一元素,再依规定交换位置后达到排序的目的。而移动次数与序列的初始排序有关。空间复杂度简单选择排序需要占用个临时空间,在交换数值时使用。 showImg(https://img-blog.csdnimg.cn/20190509221741422.gif); showImg(https://segmentfault....
摘要:,,面向切面编程。,切点,切面匹配连接点的点,一般与切点表达式相关,就是切面如何切点。例子中,注解就是切点表达式,匹配对应的连接点,通知,指在切面的某个特定的连接点上执行的动作。,织入,将作用在的过程。因为源码都是英文写的。 之前《零基础带你看Spring源码——IOC控制反转》详细讲了Spring容器的初始化和加载的原理,后面《你真的完全了解Java动态代理吗?看这篇就够了》介绍了下...
摘要:的选择器允许单个线程监视多个输入通道。一旦执行的线程已经超过读取代码中的某个数据片段,该线程就不会在数据中向后移动通常不会。 1、引言 很多初涉网络编程的程序员,在研究Java NIO(即异步IO)和经典IO(也就是常说的阻塞式IO)的API时,很快就会发现一个问题:我什么时候应该使用经典IO,什么时候应该使用NIO? 在本文中,将尝试用简明扼要的文字,阐明Java NIO和经典IO之...
阅读 2295·2021-11-08 13:13
阅读 1227·2021-10-09 09:41
阅读 1629·2021-09-02 15:40
阅读 3166·2021-08-17 10:13
阅读 2527·2019-08-29 16:33
阅读 3102·2019-08-29 13:17
阅读 3101·2019-08-29 11:00
阅读 3277·2019-08-26 13:40