网站首页 > 技术文章 正文
Vue nexTick
使用过Vue的小伙伴们都知道,Vue里的nextTick可以获取到更新后的DOM, 今天我就来讲解下nextTick里面究竟做了什么?
开始讲解前,我们需要知道了解一个概念,那就是Event Loop
Event Loop
Event Loop翻译过来就是事件循环, 一个Event Loop会包括一个或多个task队列,持续线程会从队列中取出最早进入队列的任务进行执行,被取出的任务就叫做macroTask(宏任务), 每个macroTask都有一个任务源, 每个macroTask处理完之后就从队列中取出下一个时间最早进入的macroTask再重执行
任务源:
```
1. script
2. 事件
3. Dom交互
4. I/O
5. UI Render
6. setTimeout
7. setInterval
8. requestAnimationFrame
.....
```
也就是说碰到以上几种情况就会产生一个macroTask并且推入到队列中
miscroTask(微任务)
执行完每个macroTask之后,主线程会去检查该macroTask下的microTask是否为空,如果不为空,则按照时间顺序从早到晚取出,如果途中有遇到新的microTask, 那么会继续将该microTask推入到microTask队列里
UI Render(重点)
伴随着miscroTask队列的清空,主线程就会执行UI Render, 也就是渲染界面,但是浏览器它并不会每次在UI Render任务下一定会渲染界面,视情况而言,现在主流浏览器一般都是按照60HZ 也就是16.7ms刷新频率进行渲染(不是精确估量),一个macroTask通常是小于16.7ms, 所以浏览器每次会根据情况进行渲染
总结下一个循环
1. 从macroTask队列里取出最早添加进去的
2. 开始执行task, 途中如果遇到新的macroTask,就会将其添加到macroTask队列的最后面
3. 执行完macroTask之后,event loop会去寻找microTask队列
4. 同样的道理,如果途中遇到新的microTask,将其放入该macroTask下的microTask队列最后面
5. 执行完microTask,会执行UI Render macroTask
6. 浏览器会根据现有情况决定是否更新DOM,通常是按照60HZ的频率去更新
7. 至此,一个event loop结束了
nextTick
我们开始分析nextTick
根据上图
- 我们看到nextTick的几种写法:
1. this.$nextTick(cb)
2. this.$nextTick().then(cb)
- 所有的cb都会被放入到callbacks数组里,等待一次性调用
上图中我们看到了主要是由timerFunc这个函数来进行调用回调, 那么我们下面来着重介绍这个函数,首先看下源码
我们可以看到timerFunc在不同情况下不同的赋值情况
- 首先会判断浏览器是否支持promise属性, 如果支持, timerFunc就会被赋值成Promise, 这里有个小小的问题,那就是在ios下,虽然是具备Pormise对象,并且会将它推入到microTask队列里,但是队列却不会更新,这个时候需要添加一个macroTask来强制刷新microTask队列
- MutationObserver, 相信很多人并不清楚这个Api, 这是一个能够监听DOM变化的API,并且属于microTask, 优先级低于Promise 在创建一个新的文本节点后,手动更改其文本节点来触发microTask,这里会有个小小的问题:该文本节点渲染成功后,一定能代表其他的DOM渲染成功了吗?这是个备选方案, 主要还是因为它是一个微任务,所以才使用它,并不是因为它监听了DOM
- 微任务都失败后, 退而求其次,选择setImmediate, 这是一个只有高版本IE和Edge浏览器才可能拥有的API, 其主要是用于计算大量数据的时候使用
- 最后就是setTimeout
看到这里,你会不会有疑惑?
上面的代码并没有说明nextTick是在监听DOM更新后才执行的?What????当时脑袋就duang了一下
那么接下来说的就是重中之重
DOM Tree的更新是实时的,DOM Tree的更新是实时的,DOM Tree的更新是实时的, 重要的事说3遍, 这意味着你无需去监听DOM 更新, 你对DOM的操作是能够实时得到反馈的,上一行代码操作了DOM,下一行就能获取到
那么有人就会产生疑惑了, nextTick究竟是干嘛的?
nextTick的作用是将收集Watcher从队列中一个个取出,并且更改数据,来一次性渲染DOM, 我们知道操作DOM的代价是昂贵的, 浏览器打开一个网页后会开启一个进程,进程是由线程组成的, 那么在打开的同时,
1. GUI渲染线程
2. js引擎线程(主线程)
3. EventLoop轮训处理线程
4. 其他线程,例如网络
跨线程操作代价是昂贵的,所以做到一次性渲染Dom,可以有效的优化性能!!
总结
nextTick并不是用来监听DOM变更,因为DOM变更是能够实时获取到的,它的作用是一次性更改数据,并且渲染DOM
猜你喜欢
- 2024-10-29 Vue3 - 表单的输入与绑定(vue实现表单)
- 2024-10-29 67、Vue 中如何实现一个虚拟 DOM?说说你的思路(高薪常 问)
- 2024-10-29 Vue中配合clipboard.js实现点击按钮复制内容到剪切板
- 2024-10-29 「绍棠」 Vue面试整理 一(vue项目面试中怎样去说)
- 2024-10-29 深入浅出虚拟 DOM 和 Diff 算法,及 Vue2 与 Vue3 中的区别
- 2024-10-29 这大概是理解VUE的虚拟DOM最简单的文章了
- 2024-10-29 vue-这应该是最基础了吧(vue vh)
- 2024-10-29 深入了解Vue 3中onBeforeMount钩子和DOM元素的获取时机
- 2024-10-29 Vue.js教程(六)--Vue实例的属性和方法
- 2024-10-29 Vue中多个元素、组件的过渡及列表过渡的方法示例
- 11-26Win7\8\10下一条cmd命令可查得笔记本电脑连接过的Wifi密码
- 11-26一文搞懂MySQL行锁、表锁、间隙锁详解
- 11-26电脑的wifi密码忘记了?一招教你如何找回密码,简单明了,快收藏
- 11-26代码解决忘记密码问题 教你用CMD命令查看所有连接过的WIFI密码
- 11-26CMD命令提示符能干嘛?这些功能你都知道吗?
- 11-26性能测试之慢sql分析
- 11-26论渗透信息收集的重要性
- 11-26如何查看电脑连接过的所有WiFi密码
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)