Vue中之nextTick函数源码分析详解

  

<强> 1。什么是Vue.nextTick () ?
  

  

官方文档解释如下:
  

  

在下次DOM更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。

  

<强> 2。为什么要使用nextTick& # 63;

        & lt; !DOCTYPE html>   & lt; html>   & lt; head>   & lt; title>演示Vue   & lt;脚本src=" https://tugenhua0707.github.io/vue/vue1/vue.js "祝辞& lt;/script>   & lt;/head>   & lt; body>   & lt; div id=坝τ谩北?   & lt; template>   & lt; div ref=傲斜怼北?   {{名称}}   & lt;/div>   & lt;/template>   & lt;/div>   & lt; script>   新Vue ({   埃尔:“#应用”,   数据:{   名称:“aa”   },   安装(){   this.updateData ();   },   方法:{   updateData () {   var自我=;   this.name=癰b”;   console.log(这一点。el.textContent美元);//aa   美元。nextTick(函数(){   console.log(自我。el.textContent美元);//bb   });   }   }   });   & lt;/script>   & lt;/body>   & lt;/html>      之前      

如上代码在页面视图上显示bb,但是当我在控制台打印的时候,获取的文本内容还是aa,但是使用nextTick后,获取的文本内容就是最新的内容bb了,因此在这种情况下,我们可以使用nextTick函数了。
  

  

上面的代码为什么改变this.name=癰b”;后,再使用console.log(这一点。el.textContent美元);打印的值还是aa呢?那是因为设置名称的值后,DOM还没有更新到,所以获取值还是之前的值,但是我们放到nextTick函数里面的时候,代码会在DOM更新后执行,因此DOM更新后,再去获取元素的值就可以获取到最新值了。

  

理解DOM更新:在VUE中,当我们修改了数据中的某一个值后,并不会立即反应到该el中VUE将对更改的数据放到观察者的一个异步队列中,只有在当前任务空闲时才会执行观察家队列任务,这就有一个延迟时间,因此放到nextTick函数后就可以获取该el的最新值了。如果我们把上面的nextTick改成setTimeout也是可以的。

  

<强> 3。Vue源码详解之nextTick(源码在Vue/src/核心/util/js)

  

在理解nextTick源码之前,我们先来理解下html5中新增的MutationObserver的API,它的作用是用来监听DOM变动的接口,它能监听一个DOM对象发生的子节点删除,属性修改,文本内容修改等等。
  

  

nextTick源码如下:

        出口const nextTick=(函数(){   const回调=[]   让等待=false   让timerFunc      函数nextTickHandler () {   等待=false;/*   之所以要片复制一份出来是因为有的cb执行过程中又会往回调中加入内容,比如nextTick美元的回调函数里又有nextTick美元,   那么这些应该放入到下一个轮次的nextTick去执行,所以拷贝一份,遍历完成即可,防止一直循环下去。   */const=callbacks.slice副本(0)   回调。长度=0   (让我=0;我& lt;copies.length;我+ +){   副本(我)()   }   }//nextTick行为利用了microtask队列,可以访问//通过本机的承诺。然后或MutationObserver。//MutationObserver更广泛的支持,然而它是严重困扰着//UIWebView iOS祝辞=9.3.3事件处理程序触发后联系。它//触发后完全停止工作几次……所以,如果本地//保证可用,我们将使用它:   如果*//*伊斯坦布尔忽略/*   nextTick行为利用了microtask队列,先使用Promise.resolve () (nextTickHandler)来将异步回调   放入到microtask中,承诺和MutationObserver都可以使用,但是MutationObserver在IOS9.3以上的   WebView中有错误,因此如果满足第一项的话就可以执行,如果没有原生承诺就用MutationObserver。   */如果(typeof承诺!==ㄒ濉?,isNative(承诺)){   var p=Promise.resolve ()   var logError=呃=比;{console.error (err)}   timerFunc=()=比;{   p.then (nextTickHandler) .catch (logError)//问题uiwebview,承诺。然后不完全打破,但是//可以陷入一种奇怪的状态回调是推入//microtask队列的队列没有被刷新,直到浏览器//需要做一些其他的工作,如处理一个计时器。因此,我们可以//刷新的“力”microtask队列添加一个空计时器。   如果isIOS setTimeout(等待)   }   }else if (typeof MutationObserver !==ㄒ濉?,(   isNative (MutationObserver) | |//PhantomJS和iOS 7. x   MutationObserver.toString()==='[对象MutationObserverConstructor]”   )){//使用MutationObserver原生承诺不可用,//例如PhantomJS IE11 iOS7, Android 4.4/*   创建一个MutationObserver,观察监听到DOM改动之后执行的回调nextTickHandler   */var counter=1   var观察者=new MutationObserver (nextTickHandler)   var textNode=document.createTextNode (String(柜台));//使用MutationObserver的接口,监听文本节点的字符内容   观察者。观察(textNode, {   characterData:真   });/*   每次执行timerFunc函数都会让文本节点的内容在0/1之间切换,切换之后将新赋值到那个我们MutationObserver监听的文本节点上去。   */timerFunc=()=比;{   counter=(计数器+ 1)% 2   textNode。data=https://www.yisu.com/zixun/String(柜台)   }   其他}{//回退setTimeout/*   如果上面的两种都不支持的话,我们就使用setTimeout来执行   */timerFunc=()=> {   setTimeout (nextTickHandler, 0)   }   }      返回函数queueNextTick (cb吗?:函数,ctx吗?:对象){   让_resolve   callbacks.push (()=> {   如果(cb) {   尝试{   cb.call (ctx)   }捕捉(e) {   handleError (e、ctx、“nextTick”)   }   }else if (_resolve) {   _resolve (ctx)   }   });/*如果等待为真的,表明本轮事件循环中已经执行过timerFunc (nextTickHandler,0) */如果(待定){   等待=true   timerFunc ()   }   如果(!cb,,typeof承诺!==ㄒ濉?{   返回新的承诺((解决,拒绝)=比;{   _resolve=解决   })   }   }   })()      

Vue中之nextTick函数源码分析详解