原理性的货色就会文字较多,请耐下心来,细细品味

Vue中DOM更新机制

当你威风凛凛地应用Vue大展宏图的时候,忽然发现,咦,我明明对这个数据进行更改了,然而当我获取它的时候怎么是上一次的值(自己比拟懒,就不具体举例了)

此时,Vue就会说:“小样,这你就不懂了吧,我的DOM是异步更新的呀!!!”

简略的说,Vue的响应式并不是只数据发生变化之后,DOM就立即发生变化,而是依照肯定的策略进行DOM的更新。这样的益处是能够防止一些对DOM不必要的操作,进步渲染性能。

在Vue官网文档中是这样阐明的:

可能你还没有留神到,Vue异步执行DOM更新。只有察看到数据变动,Vue将开启一个队列,并缓冲在同一事件循环中产生的所有数据扭转。如果同一个watcher被屡次触发,只会被推入到队列中一次。这种在缓冲时去除反复数据对于防止不必要的计算和DOM操作上十分重要。而后,在下一个的事件循环“tick”中,Vue刷新队列并执行理论 (已去重的) 工作。

文言一点就是说,其实这是和JS当中的事件循环是非亲非故的,就是Vue不可能对每一个数据变动都做一次渲染,它会把这些变动先放在一个异步的队列当中,同时它还会对这个队列外面的操作进行去重,比方你批改了这个数据三次,它只会保留最初一次。这些变动是都能够通过队列的模式保存起来,那当初的问题就来到了,那vue是在事件循环的哪个机会来对DOM进行批改呢?

Vue有两种抉择,一个是在本次事件循环的最初进行一次DOM更新,另一种是把DOM更新放在下一轮的事件循环当中。z这时,尤雨溪拍了拍胸脯说:“这两种办法,我都有!” 然而因为本轮事件循环最初执行会比放在下一轮事件循环要快很多,所以Vue优先选择第一种,只有当环境不反对的时候才触发第二种机制。(结尾的链接让你懂事件循环)

尽管性能上进步了很多,但这个时候问题就呈现了,咱们都晓得在一轮事件循环中,同步执行栈中代码执行实现之后,才会执行异步队列当中的内容,那咱们获取DOM的操作是一个同步的呀!!那岂不是尽管我曾经把数据改掉了,然而它的更新异步的,而我在获取的时候,它还没有来得及改,所以会呈现文章结尾的那个问题。

这。。。我的确须要进行这样操作,那这么办呢??

没关系啦,尤大很贴心的为咱们提供了Vue.$nextTick()

Vue.$nextTick()

其实一句话就能够把$nextTick这个货色讲明确:就是你放在$nextTick 当中的操作不会立刻执行,而是等数据更新、DOM更新实现之后再执行,这样咱们拿到的必定就是最新的了。

再精确一点来讲就是$nextTick办法将回调提早到下次DOM更新循环之后执行。(看不懂这句人话的,能够看下面[狗头])

意思咱们都懂了,那$nextTick是怎么实现这个神奇的性能的呢? 外围如下:

Vue在外部对异步队列尝试应用原生的Promise.thenMutationObserversetImmediate,如果执行环境不反对,则会采纳 setTimeout(fn, 0)代替。

认真地看这句话,你就能够发现这不就是利用 JavaScript 的这些异步回调工作队列,来实现 Vue 框架中本人的异步回调队列。这其实就是一个典型的将底层 JavaScript 执行原理利用到具体案例中的示例。

我在这里略微总结一下:就是$nextTick将回调函数放到微工作或者宏工作当中以提早它地执行程序;(总结的也比拟懒)

重要的是了解源码中它的三个参数的意思:

  • callback:咱们要执行的操作,能够放在这个函数当中,咱们没执行一次$nextTick就会把回调函数放到一个异步队列当中;
  • pending:标识,用以判断在某个事件循环中是否为第一次退出,第一次退出的时候才触发异步执行的队列挂载
  • timerFunc:用来触发执行回调函数,也就是Promise.thenMutationObserversetImmediatesetTimeout的过程

了解之后,在看整个$nextTick外面的执行过程,其实就是把一个个$nextTick中的回调函数压入到callback队列当中,而后依据事件的性质期待执行,轮到它执行的时候,就执行一下,而后去掉callback队列中相应的事件。

应用

说了这么多,怎么用它呢? 很简略很简略

mounted: function () {  this.$nextTick(function () {    // Code that will run only after the    // entire view has been rendered  })}

应用场景

  1. created中获取DOM的操作须要应用它
  2. 就是咱们下面的例子,你如果想要获取最新值,就用它
  3. 还有一些第三方插件应用过程中,应用到的状况,具体问题具体分析

参考 前端进阶面试题具体解答

补充

之前我始终搞不懂一个的问题,$nextTick既然把它传入的办法变成微工作了,那它和其它微工作的执行程序是怎么的呢?

这简略来说就是谁先挂载Promise对象的问题,在调用$nextTick办法时就会将其闭包外部保护的执行队列挂载到Promise对象,在数据更新时Vue外部首先就会执行$nextTick办法,之后便将执行队列挂载到了Promise对象上,其实在明确JsEvent Loop模型后,将数据更新也看做一个$nextTick办法的调用,并且明确$nextTick办法会一次性执行所有推入的回调,就能够明确执行程序的问题了

还有$nextTicknextTick区别就是nextTick多了一个context参数,用来指定上下文。但两个的实质是一样的,$nextTick是实例办法,nextTick是类的静态方法而已;实例办法的一个益处就是,主动给你绑定为调用实例的this罢了。