001 vue响应式的异步渲染
问题场景:
// DOM节点 <template> <div> <div v-if="isShow" ref="show">{{data1}}</div> <div v-else ref="hidden">{{data2}}</div> </div> </template> <script> this.ishow = false console.log(this.$refs.hidden.offsetHeight) </script>
此时,会打印出 undefined,很奇怪呀
分析:
这是因为vue是数据驱动视图的,即数据更新之后,vue会自动去更新视图,但是这个更新是异步的。即当数据更新之后,试图还未更新,此时继续操作更新后的dom,就会出现和预期不一样的结果。
什么叫异步呢?
当执行一段js代码时,引起了页面的数据变化,而这些数据变化会引起dom树的更新,但这个dom树的更新并不是立即执行的。此时,vue会将更新dom数的这一任务放到 异步更新队列 中去排队,在下一轮事件循环中执行。
为什么vue采用异步更新策略呢?
一句话:为了提升vue的性能,减少资源消耗
我们可能在uige方法中对dom操作n多次(比如for循环对dom进行操作),如果每次都立即对dom进行更新,那么dom会频繁更新,这显然效率低下,异步更新,可以实现多次操作dom,一次更新视图。
nextTick()的使用:
1. nextTick方法时解决上述异步问题的一个思路。this.$nextTick(callback)
2. nextTick的核心是利用了如 Promise 、MutationObserver、setImmediate、setTimeout的原生 JS 方法来模拟对应的微/宏任务的实现;
3. 它将传入的回调函数放在微/宏任务队列中等待执行,我们将更新数据之后,对更新后dom的操作放在$nextTick中去执行,就可以保证在dom更新完成之后,实现对dom的操作(因为这一步在队列中排在dom更新之后)
nextTick()的使用原理:
nextTick内部对异步更新队列,按顺序采用Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替,进行降级处理。
降级的目的:就是在环境支持的情况下,尽早的去更新dom。
优先选择微任务的原因:在微任务中更新队列是会比在宏任务中更新少一次UI渲染的。
nextTick的更新:
过程:
1. Vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环 (event loop) 中 观察到数据变化的 watcher 推送进这个队列。
2. 如果这个watcher被触发多次,只会被推送到队列一次。这种缓冲行为可以有效的去掉重复数据,避免不必要的计算和Dom操作。
3. 而在下一个事件循环时,Vue会清空队列,并进行必要的DOM更新。
源码解析:
1. 数据变化时,通过notify通知watcher进行更新操作;
2. 通过subs[i].update依次调用watcher的update(未更新视图);
3. 将watcher放到队列中,在queueWatcher会根据watcher的id进行去重(多个属性依赖一个watcher),如果队列中没有该watcher就会将该watcher添加到队列中(未更新视图);
4. 通过nextTick异步执行flushSchedulerQueue方法刷新watcher队列(更新视图)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2020-06-09 008 Javascript(093 - 100)