全面解析Vue中的$nextTick


Posted in Vue.js onDecember 24, 2020

当在代码中更新了数据,并希望等到对应的Dom更新之后,再执行一些逻辑。这时,我们就会用到$nextTick

funcion callback(){
 //等待Dom更新,然后搞点事。
}
$nextTick(callback);

官方文档对nextTick的解释是:

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

那么,Vue是如何做的这一点的,是不是在调用修改Dom的Api之后(appendChild, textContent = "xxxxx" 诸如此类),调用了我们的回调函数?
实际上发生了什么呢。

源码

nextTick的实现逻辑在这个文件里:

vue/src/core/util/next-tick.js

我们调用的this.$nextTick实际上是这个方法:

export function nextTick (cb?: Function, ctx?: Object) {
 let _resolve
 callbacks.push(() => {
  if (cb) {
   try {
    cb.call(ctx)
   } catch (e) {
    handleError(e, ctx, 'nextTick')
   }
  } else if (_resolve) {
   _resolve(ctx)
  }
 })
 if (!pending) {
  pending = true
  timerFunc()
 }
 // $flow-disable-line
 if (!cb && typeof Promise !== 'undefined') {
  return new Promise(resolve => {
   _resolve = resolve
  })
 }
}

可以看到

  1. 回调函数被存放到了一个数组里:callbacks。
  2. 如果没有传递回调函数,这个方法会返回一个Promise,然后吧reslove当成回调函数放到flushCallbacks中。所以文档解释了把本该当成回调函数的callbacks放到then里的用法。
  3. 然后,有一个变量叫pending,如果不在pending中,则执行函数timerFunc。而且pending默认等于false。
  4. flushCallbacks这个函数会一口气执行所有回调函数。

timerFunc

timerFunc定义在这里

可以看到timerFunc是在一个已resolve了的Promise的then 中执行了flushCallbacks.

利用了js事件循环的微任务的机制

所以,每当我们调用$nextTick,如果pending为false,就会调用timerFunc,然后timerFunc会把flushCallbacks给塞到事件循环的队尾,等待被调用。

if (typeof Promise !== 'undefined' && isNative(Promise)) {
 const p = Promise.resolve()
 timerFunc = () => {
  p.then(flushCallbacks)
 }
}

flushCallbacks

然后在这个文件里还有一个函数叫:flushCallbacks
用来把保存的回调函数给全执行并清空。

function flushCallbacks () {
 pending = false
 const copies = callbacks.slice(0)
 callbacks.length = 0
 for (let i = 0; i < copies.length; i++) {
  copies[i]()
 }
}

pending

什么时候pending为true呢?

从timerFunc被调用到flushCallbacks被调用期间pending为true

即一个事件循环周期

在pending期间加入的回调函数,会被已经等待执行的flushCallbacks函数给执行。

核心机制

看完源码,发现除了利用了一个微任务的机制,和Dom更新一点关系都没有哇。

其实调用nextTick的不仅是开发者,Vue更新Dom时,也用到了nextTick。

开发者更新绑定的数据之后,Vue就会立刻调用nextTick,把更新Dom的回调函数作为微任务塞到事件循环里去。

于是,在微任务队列中,开发者调用的nextTick的回调函数,就一定在更行Dom的回调函数之后执行了。

但是问题又来了,根据浏览器的渲染机制,渲染线程是在微任务执行完成之后运行的。渲染线程没运行,怎么拿到Dom呢?

因为,渲染线程只是把Dom树渲染成UI而已,Vue更新Dom之后,在Dom树里,新的Dom节点已经存在了,js线程就已经可以拿到新的Dom了。除非开发者读取Dom的计算属性,触发了强制重流渲染线程才会打断js线程。

总结

  1. 首先timerFunc函数负责把回调函数们都丢到事件循环的队尾
  2. 然后,nextTick函数负责把回调函数们都保存起来。
  3. 调用nextTick函数时会调用timerFunc函数
  4. Vue更新Dom也会使用nextTick,而且在开发者调用nextTick之前。
  5. 因为4中的先后关系和事件循环的队列性质,确保了开发者的nextTick的回调一定在Dom更新之后

以上就是解析Vue中的$nextTick的详细内容,更多关于Vue中的$nextTick的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
VUE中鼠标滚轮使div左右滚动的方法详解
Dec 14 Vue.js
vue导入.md文件的步骤(markdown转HTML)
Dec 31 Vue.js
Vue看了就会的8个小技巧
Jan 21 Vue.js
学习 Vue.js 遇到的那些坑
Feb 02 Vue.js
vue前端工程的搭建
Mar 31 Vue.js
vue项目中的支付功能实现(微信支付和支付宝支付)
Feb 18 Vue.js
vue实现滑动解锁功能
Mar 03 Vue.js
vue组件vue-esign实现电子签名
Apr 21 Vue.js
Vue操作Storage本地化存储
Apr 29 Vue.js
vue ant design 封装弹窗表单的使用
Jun 01 Vue.js
vue递归实现树形组件
Jul 15 Vue.js
Vue router配置与使用分析讲解
Dec 24 Vue.js
vue实现登录、注册、退出、跳转等功能
Dec 23 #Vue.js
vue下拉刷新组件的开发及slot的使用详解
Dec 23 #Vue.js
Vue3 实现双盒子定位Overlay的示例
Dec 22 #Vue.js
详解Vue的异步更新实现原理
Dec 22 #Vue.js
Vue组件简易模拟实现购物车
Dec 21 #Vue.js
vue实现购物车的小练习
Dec 21 #Vue.js
Vue实现小购物车功能
Dec 21 #Vue.js
You might like
解析php中两种缩放图片的函数,为图片添加水印
2013/06/14 PHP
访问编码后的中文URL返回404错误的解决方法
2014/08/20 PHP
php中substr()函数参数说明及用法实例
2014/11/15 PHP
jquery下jstree简单应用 - v1.0
2011/04/14 Javascript
点击页面其它地方隐藏该div的两种思路
2013/11/18 Javascript
window.location.href IE下跳转失效的解决方法
2014/03/27 Javascript
jquery使用ul模拟select实现表单美化的方法
2015/08/18 Javascript
JavaScript的Backbone.js框架入门学习指引
2016/05/07 Javascript
JSON与String互转的实现方法(Javascript)
2016/09/27 Javascript
JS中cookie的使用及缺点讲解
2017/05/13 Javascript
JS实现页面打印(整体、局部)
2017/08/18 Javascript
vue实现打印功能的两种方法
2018/09/07 Javascript
vue单页面在微信下只能分享落地页的解决方案
2019/04/15 Javascript
Python 的 with 语句详解
2014/06/13 Python
利用python批量检查网站的可用性
2016/09/09 Python
利用Python实现微信找房机器人实例教程
2019/03/10 Python
在vscode中配置python环境过程解析
2019/09/28 Python
使用python 对验证码图片进行降噪处理
2019/12/18 Python
如何用python 操作zookeeper
2020/12/28 Python
python 下载文件的几种方法汇总
2021/01/06 Python
解决html5中video标签无法播放mp4问题的办法
2017/05/07 HTML / CSS
使用C#编写创建一个线程的代码
2013/01/22 面试题
Java如何获得ResultSet的总行数
2016/09/03 面试题
交通安全演讲稿
2014/01/07 职场文书
大课间活动制度
2014/01/18 职场文书
中专毕业生个人职业生涯规划
2014/02/19 职场文书
2014年社区植树节活动方案
2014/02/28 职场文书
一年级评语大全
2014/04/23 职场文书
三八妇女节活动总结
2014/05/04 职场文书
服装仓管员岗位职责
2014/06/17 职场文书
2014年网络管理员工作总结
2014/12/01 职场文书
本科毕业论文致谢怎么写
2015/05/14 职场文书
入党积极分子党小组意见
2015/06/02 职场文书
教师实习自我鉴定总结
2019/08/20 职场文书
Python 数据结构之十大经典排序算法一文通关
2021/10/16 Python
win7配置本地ftp服务器的图文教程
2022/08/05 Servers