乐趣区

关于前端:VuenextTick的原理是什么vue面试进阶

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

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 罢了。

退出移动版