共计 2354 个字符,预计需要花费 6 分钟才能阅读完成。
原理性的货色就会文字较多,请耐下心来,细细品味
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 面试题解答 前端 vue 面试题具体解答
Vue.$nextTick()
其实一句话就能够把 $nextTick
这个货色讲明确:就是你放在$nextTick
当中的操作不会立刻执行,而是等数据更新、DOM 更新实现之后再执行,这样咱们拿到的必定就是最新的了。
再精确一点来讲就是 $nextTick
办法将回调提早到下次 DOM 更新循环之后执行。(看不懂这句人话的,能够看下面[狗头])
意思咱们都懂了,那 $nextTick
是怎么实现这个神奇的性能的呢?外围如下:
Vue
在外部对异步队列尝试应用原生的Promise.then
、MutationObserver
和setImmediate
,如果执行环境不反对,则会采纳setTimeout(fn, 0)
代替。
认真地看这句话,你就能够发现这不就是利用 JavaScript 的这些异步回调工作队列,来实现 Vue 框架中本人的异步回调队列。这其实就是一个典型的将底层 JavaScript 执行原理利用到具体案例中的示例。
我在这里略微总结一下:就是 $nextTick
将回调函数放到微工作或者宏工作当中以提早它地执行程序;(总结的也比拟懒👶)
重要的是了解源码中它的三个参数的意思:
- callback:咱们要执行的操作,能够放在这个函数当中,咱们没执行一次
$nextTick
就会把回调函数放到一个异步队列当中; - pending:标识,用以判断在某个事件循环中是否为第一次退出,第一次退出的时候才触发异步执行的队列挂载
- timerFunc:用来触发执行回调函数,也就是
Promise.then
或MutationObserver
或setImmediate
或setTimeout
的过程
了解之后,在看整个 $nextTick
外面的执行过程,其实就是把一个个 $nextTick
中的回调函数压入到 callback 队列当中,而后依据事件的性质期待执行,轮到它执行的时候,就执行一下,而后去掉 callback 队列中相应的事件。
应用
说了这么多,怎么用它呢?很简略很简略
mounted: function () {this.$nextTick(function () {
// Code that will run only after the
// entire view has been rendered
})
}
应用场景
- created 中获取 DOM 的操作须要应用它
- 就是咱们下面的例子,你如果想要获取最新值,就用它
- 还有一些第三方插件应用过程中,应用到的状况,具体问题具体分析
补充
之前我始终搞不懂一个的问题,$nextTick
既然把它传入的办法变成微工作了,那它和其它微工作的执行程序是怎么的呢?
这简略来说就是谁先挂载 Promise
对象的问题,在调用 $nextTick
办法时就会将其闭包外部保护的执行队列挂载到 Promise
对象,在数据更新时 Vue
外部首先就会执行 $nextTick
办法,之后便将执行队列挂载到了 Promise
对象上,其实在明确 Js
的Event Loop
模型后,将数据更新也看做一个 $nextTick
办法的调用,并且明确 $nextTick
办法会一次性执行所有推入的回调,就能够明确执行程序的问题了
还有 $nextTick
和nextTick
区别就是 nextTick
多了一个 context 参数,用来指定上下文。但两个的实质是一样的,$nextTick
是实例办法,nextTick
是类的静态方法而已;实例办法的一个益处就是,主动给你绑定为调用实例的 this
罢了。