博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
18.Vue.nextTick实现
阅读量:6279 次
发布时间:2019-06-22

本文共 2617 字,大约阅读时间需要 8 分钟。

用法:

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

疑惑:

怎么实现的延迟回调

原理:

  1. JavaScript语言的一大特点就是单线程,同一个时间只能做一件事
  2. JavaScript任务可以分为两种,一种是同步任务,一种是异步任务
  3. 异步任务大致分为,宏任务,和微任务
  4. 所有同步任务都在主线程上执行,形成一个执行栈
  5. 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
  6. 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列"中的微任务,其次是宏任务,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
  7. 主线程不断重复上面的第6步。

vue实现:

vue 大多数情况下优先使用微任务, 在添加事件中使用宏任务 意思是在事件中使用Vue.nextTick 使用宏任务, 其他情况下使用微任务

vue nextTick 宏任务实现

  • 优先检测 setImmediate
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {  macroTimerFunc = () => {    setImmediate(flushCallbacks)  }}复制代码

setImmediate 浏览器支持情况

  • 其次检测 MessageChannel 支持情况
else if (typeof MessageChannel !== 'undefined' && (  isNative(MessageChannel) ||  // PhantomJS  MessageChannel.toString() === '[object MessageChannelConstructor]')) {  const channel = new MessageChannel()  const port = channel.port2  channel.port1.onmessage = flushCallbacks  macroTimerFunc = () => {    port.postMessage(1)  }} 复制代码

MessageChannel 浏览器支持情况

  • 上面都不支持就使用最原始的setTimeout
else {  /* istanbul ignore next */  macroTimerFunc = () => {    setTimeout(flushCallbacks, 0)  }}复制代码

vue nextTick 微任务实现

  • 优先检测 Promise
if (typeof Promise !== 'undefined' && isNative(Promise)) {  const p = Promise.resolve()  microTimerFunc = () => {    p.then(flushCallbacks)    // in problematic UIWebViews, Promise.then doesn't completely break, but    // it can get stuck in a weird state where callbacks are pushed into the    // microtask queue but the queue isn't being flushed, until the browser    // needs to do some other work, e.g. handle a timer. Therefore we can    // "force" the microtask queue to be flushed by adding an empty timer.    if (isIOS) setTimeout(noop)  }}复制代码

Promise 浏览器支持情况

  • 如果不支持Promise, 还是使用宏任务
else {  // fallback to macro  microTimerFunc = macroTimerFunc}复制代码

vue中什么地方用宏任务,什么地方用微任务?

从源码中可以看出,在DOM事件中使用Vue.nextTick 默认使用宏任务, 其他地方使用Vue.nextTick默认使用微任务。

其实从源码中注释中可以看出Vue最开始都是使用微任务方式,后面出现了bug,才引入了宏任务方式

// Here we have async deferring wrappers using both microtasks and (macro) tasks.// In < 2.4 we used microtasks everywhere, but there are some scenarios where// microtasks have too high a priority and fire in between supposedly// sequential events (e.g. #4521, #6690) or even between bubbling of the same// event (#6566). However, using (macro) tasks everywhere also has subtle problems// when state is changed right before repaint (e.g. #6813, out-in transitions).// Here we use microtask by default, but expose a way to force (macro) task when// needed (e.g. in event handlers attached by v-on).复制代码

产考资料:

讨论地址:

转载于:https://juejin.im/post/5c0682e5518825741f62881e

你可能感兴趣的文章
PHP字符编码转换类3
查看>>
rsync同步服务配置手记
查看>>
http缓存知识
查看>>
Go 时间交并集小工具
查看>>
iOS 多线程总结
查看>>
webpack是如何实现前端模块化的
查看>>
TCP的三次握手四次挥手
查看>>
关于redis的几件小事(六)redis的持久化
查看>>
package.json
查看>>
webpack4+babel7+eslint+editorconfig+react-hot-loader 搭建react开发环境
查看>>
Maven 插件
查看>>
初探Angular6.x---进入用户编辑模块
查看>>
计算机基础知识复习
查看>>
【前端词典】实现 Canvas 下雪背景引发的性能思考
查看>>
大佬是怎么思考设计MySQL优化方案的?
查看>>
<三体> 给岁月以文明, 给时光以生命
查看>>
Android开发 - 掌握ConstraintLayout(九)分组(Group)
查看>>
springboot+logback日志异步数据库
查看>>
Typescript教程之函数
查看>>
Android 高效安全加载图片
查看>>