当前位置: 首页 > Web前端 > vue.js

NextTick源码分析

时间:2023-03-31 23:58:21 vue.js

1。阅读整个代码就像画一幅画一样。忌讳从细节入手(比如逐行阅读)。先折叠详细代码,整体观察nextTick源码。折叠后的代码如下图所示,整体代码结构见上图。可以看到nextTick相当于一个立即执行函数。函数执行后,内部返回另一个匿名函数function(cb,ctx)。从命名语义上分析,第一个参数cb是一个回调函数,这里的ctx应该是一个context。在return返回之前,函数被调用之后,函数内部用var定义了三个参数,用function声明了一个函数。不管这些变量是做什么用的。就从语义命名的角度来分析一下:callbacks可能是一个callbacks的数组,以后有多个callback的时候可以用来模拟队列的执行效果。pending是一个布尔值。pending这个词会出现在接口请求中,可以用来标识某个状态是否在进行中。timeFunc似乎暂时不知道该做什么。nextTickHandler函数被忽略。需要的时候看看吧。以上是代码的初步分析。2.逐行分析看完大代码块结构后,就可以按照js引擎解析代码的先后顺序来分析源码了。看完前面的变量和函数声明,是时候解析if语句了。在if条件中,有一个判断:typeofMutationObserver!=='undefined'&&!hasMutationObserverBug。MutationObserver是做什么的?A.MutationObserver度娘说他“提供了监控DOM树变化的能力”。大白话粗略的理解就是他可以监听dom的修改。是HTML5中的一项新功能。MutationObserver()这个属性提供了一个构造函数MutationObserver()?通过newMutationObserver()可以得到一个新的观察者,当指定的DOM事件被触发时会调用指定的回调函数。“MutationObserver对DOM的观察不会立即开始;并且必须先调用observe()方法来确定要监视DOM的哪一部分以及响应哪些变化。”?observe(target[,options])开启观察者,根据配置开始监听指定的DOM。没有返回值。接收两个参数:target是一个Node/Element节点,表示要监控的DOM对象。options是监听配置,配置target的哪些变化需要触发回调。配置项相关参数参考MutationObserverInit配置字典attributes:true|false,观察被监控DOM元素的任何属性值变化attributeFilter:监控多个具体属性,放在一个数组中。例如:['class','id','src']characterData:true|false,如果为true,则当指定要监听的文本节点内容发生变化时,会调用callback回调。childList:true|false,如果为true,则监听指定DOM对象的新子节点的添加或删除,还有其他几个扩展。参考MutationObserverInit配置字典>?>>调用observe()方法时,childList、attributes或characterData三个属性至少其中之一必须为true,否则会抛出TypeError异常。>>?语法`//获取所需的观察元素varelementToObserve=document.querySelector("#targetElementId");//构造一个MutationObserver对象并传递一个函数作为参数varobserver=newMutationObserver(callback);//启用观察者observe(),监听的DOM对象为elementToObserveobserver.observe(elementToObserve,{//监听规则,当子节点或目标节点的整个节点树中的所有节点都被添加/删除时,上述回调回调函数被触发subtree:true,childList:true});`当MutationObserver监听到我们注册的DOM发生变化时(无论是DOM节点变化还是DOM属性发生变化,主要是监听DOM的哪一部分发生变化或者取决于你的配置项),回调函数callback会被调用._(有点像我们发给云云的DOM对象的间谍,监视我们指定的dom,有变化时通知我们)_callback回调函数有两个参数:一个是描述所有触发变化的MutationRecord对象数组,和另一个是One是调用该函数的MutationObserver对象。但这是这个属性的用法。在VUE关于nextTick的源码中,callback的这两个参数并没有用于该属性。我不会在这里解释。具体可以看这里MDNMutationObserver()B.if条件成立。掌握了MutationObserver及其用法后,回归源码。if里面的代码很好理解:首先,作为一个新的H5特性,它的兼容性不是很好(IE爸爸:看看我!)所以vue在这里做了容错,先判断MutationObserver的类型是不是“undefined”检查浏览器是否支持该功能。如果这个属性是支持的,没有bug,那么就去if语句的内容。if语句中有三个变量:`varcounter=1vartextNode=document.createTextNode(counter)varobserver=newMutationObserver(nextTickHandler)`定义了一个计数器编号textNode变量用于存储文档创建的文本节点。创建文本节点。文本内容是计数器的值。新的MutationObserver()行。相信有了以上知识点的铺垫,大家就会很容易理解了。构造并返回一个新的观察者,用于在指定DOM(即上面的textNode)发生变化时调用回调函数nextTickHandler。接下来,观察者根据MutationObserverInit配置字段的设置监听textNode元素。当textNode文本节点的文本内容发生细微变化时,会立即触发nextTickHandler回调函数。`varobserver=newMutationObserver(nextTickHandler)observer.observe(textNode,{characterData:true})`下一步是将代码顶部定义的timerFunc变量分配给一个函数。`timerFunc=function(){counter=(counter+1)%2textNode.data=counter}`通过函数内部的(counter+1)%2的表达思路,每次都会改变counter的值调用的timeFunc函数变为0/1。并且通过将计数器的变化值赋值给textNode节点,可以改变textNode文本节点的内容,从而触发观察者监听,然后调用nextTickHandler回调函数。至此,if语句的内部流程就完成了。趁热打铁吧,先别看else里的内容(可以认为应该是不兼容MutationObserver后的降级方案,按照if里的思路,应该看看nextTickHandler里有什么。监听DOM变化后,每次回调完成?C、nextTickHandler()逐句看代码:`//1pending=false`每次调用nextTickHandler时,先将pending设置为false,思路猜测pending是一个锁已经进一步获取Verify.`//2varcopies=callbacks.slice(0)`使用数组的slice()方法,传入start下标0,不传end下标,获取新的浅拷贝回调数组,并将其复制到副本。`//3callbacks=[]`将回调重新分配给空数组`//4for(vari=0;i