nextTick

定义:将回调推迟到下一个 DOM 更新周期之后执行,在更改了一些数据以等待 DOM 更新后立即使用它
在实际中使用这个方法一般是用于组件更新,你需要获取更新后的数据,所以使用nextTick等待DOM更新

// vue3中的语法对比vue2做了一些改动
import { createApp, nextTick } from 'vue'
const app = createApp({setup() {const message = ref('Hello!')const changeMessage = async newMessage => {message.value = newMessage// 这里的value是旧值await nextTick()// nextTick后获取的就是DOM更新后的valueconsole.log('Now DOM is updated')}}
})
  • 这个api使用时相当简单,而且相当容易理解,但是为了知其意,还是要翻一下源码了解它的执行机制
export function nextTick(this: ComponentPublicInstance | void,fn?: () => void
): Promise<void> {const p = currentFlushPromise || resolvedPromisereturn fn ? p.then(this ? fn.bind(this) : fn) : p
}
  • 上面是vue源码中nextTick的实现,为了搞清楚实现逻辑,就必须搞懂currentFlushPromise这个变量的含义,所以要从任务的调度机制开始分析

任务调度

首先这个调度机制的功能在runtime-corescheduler文件

  • API
// 这个文件会抛出以下几个API函数
nextTick(){} // 将函数在任务队列清空后执行
queueJob(){} // 添加任务并开始执行任务队列
invalidateJob(){} // 删除任务
queuePreFlushCb(){} // 添加前置回调函数并开始执行任务队列
queuePostFlushCb(){} // 添加后置回调函数并开始执行任务队列
flushPreFlushCbs(){} // 执行前置回调函数
flushPostFlushCbs(){} // 执行后置回调函数
  • 我们首先要知道几个关键变量
let isFlushing = false // 是否正在清空任务队列
let isFlushPending = false // 清队任务已创建,等待清空状态
const queue: SchedulerJob[] = [] // 任务队列
let flushIndex = 0 // 当前正在执行的任务在任务队列中的索引
  • 然后我们从queueJob这个函数开始
/* 这个函数主要是将一个任务(job)进行入队操作然后在满足条件的情况下启动清空队列任务(queueFlush)*/
export function queueJob(job: SchedulerJob) {/*** 任务可入队逻辑* 1. 任务队列为空* 2. 待入队任务不能存在于任务队列中(按情况分析)*/if ((!queue.length ||!queue.includes(job,/* 在正在清空队列且当前待入队任务是可以递归时,说明当前任务一定和当前正在执行任务是同一任务,所以+1,就是为了保证待入队任务和正在执行任务相同,但不能和后面待执行任务相同*/isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex)) &&job !== currentPreFlushParentJob) {// 二分查找任务在队列中的位置const pos = findInsertionIndex(job)if (pos > -1) {queue.splice(pos, 0, job)} else {queue.push(job)}queueFlush()}
}
  • queueFlush
function queueFlush() {/**清队任务创建后禁止再次创建更多的清队任务因为在入队操作完成后,flushJobs会在一次递归中将任务队列全部清空,所以只需要一次清队任务即可*/if (!isFlushing && !isFlushPending) {isFlushPending = true/* 清队任务创建成功,并记录下当前清队任务,这个标记可以用于nextTick创建自定义函数,说明nextTick的执行时机是在清队任务后的,其实从这个地方就可以理解nextTick的执行原理了*/currentFlushPromise = resolvedPromise.then(flushJobs)}
}
  • flushJobs
// 清空任务队列
function flushJobs(seen?: CountMap) {isFlushPending = false // 关闭清队任务等待状态isFlushing = true // 开启正在清空队列状态if (__DEV__) {seen = seen || new Map()}// 清空前置回调任务队列flushPreFlushCbs(seen)/* 任务队列中的任务根据ID进行排序的原因1. 因为组件更新是从父组件到子组件的,而任务更新是在数据源更新时触发的,所以为了更新任务的顺序就需要进行排序2. 如果在父组件更新期间已经卸载了组件,那么子组件的更新任务就可以跳过*/queue.sort((a, b) => getId(a) - getId(b))try {// 遍历任务队列for (flushIndex = 0; flushIndex < queue.length; flushIndex++) {const job = queue[flushIndex]if (job && job.active !== false) {if (__DEV__ && checkRecursiveUpdates(seen!, job)) {continue}// 执行当前任务callWithErrorHandling(job, null, ErrorCodes.SCHEDULER)}}} finally {// 重置当前任务索引flushIndex = 0// 清空任务队列queue.length = 0// 执行后置回调任务队列flushPostFlushCbs(seen)// 重置清队任务的状态isFlushing = falsecurrentFlushPromise = null/* 因为清队任务执行期间也会有任务入队,所以为了清队执行完成就需要判断各任务队列的长度,然后递归执行*/if (queue.length ||pendingPreFlushCbs.length ||pendingPostFlushCbs.length) {flushJobs(seen)}}
}

总结

  • nextTick的执行时机是在任务队列(前置、主任务、后置)清除后的,currentFlushPromise是清队任务的promise标记
  • 任务队列执行顺序:执行前置回调任务队列 -> 执行主任务队列 -> 执行后置回调任务队列

解析nextTick---vue3任务调度相关推荐

  1. 网络请求框架OkHttp4的使用与原理解析01:任务调度与拦截器分析

    OkHttp任务调度流程: 1. OkHttpClient构建过程分析 案例: OkHttpClient client = new OkHttpClient.Builder().addIntercep ...

  2. Vue3源码解析01--Vue3初探

    Vue3 源码解析 01 - Vue3 浅谈 前言 最近几个月一直忙于公司搬砖,导致都没有时间学习了.正好这段时间慢慢恢复了正常工作的作息,赶紧学习一下最新发布的 Vue3 框架. 为什么有 Vue3 ...

  3. vue created 调用方法_深入解析 Vue 的热更新原理,偷学尤大的秘籍?

    大家都用过 Vue-CLI 创建 vue 应用,在开发的时候我们修改了 vue 文件,保存了文件,浏览器上就自动更新出我们写的组件内容,非常的顺滑流畅,大大提高了开发效率.想知道这背后是怎么实现的吗, ...

  4. SDU信息门户(10)前端vue3.0代码分析

    2021SC@SDUSC 目录 一.引言 二.代码分析 1.答辩检查组件 2.文件系统组件 3.公告组件 4.教师发布题目组件 三.总结 一.引言 SDU信息门户中前端主要使用了Vue3.0的技术,这 ...

  5. @Scheduled源码解析

    文章目录 @Scheduled源码解析 解析部分 执行部分 小结 @Scheduled源码解析 解析部分 定时任务调度的基础是ScheduledAnnotationBeanPostProcessor类 ...

  6. 【干货】写给初中级前端的高级进阶指南

    以下文章来源于掘金开发者社区,作者晨曦时梦见兮 我曾经一度很迷茫,在学了Vue.React的实战开发和应用以后,好像遇到了一些瓶颈,不知道该怎样继续深入下去.相信这也是很多一两年经验的前端工程师所遇到 ...

  7. 写给初中级前端的高级进阶指南(万字长文,建议收藏)

    前言 由于公众号文章不允许外链,需要跳转文中链接的同学可以在脚注里找到各个的资源链接,也可以通过点击阅读原文更加方便的跳转链接. 我曾经一度很迷茫,在学了 Vue.React 的实战开发和应用以后,好 ...

  8. 2020年 30K的前端架构面试题总结(持续更新)

    vue部分 vue父子组件通信 props,$ emit , vuex , provide/inject , $ attrs/$ listeners,$root , $parent, $refs, e ...

  9. 写给初中级前端的高级进阶指南(万字路线)

    前言 我曾经一度很迷茫,在学了 Vue.React 的实战开发和应用以后,好像遇到了一些瓶颈,不知道该怎样继续深入下去.相信这也是很多一两年经验的前端工程师所遇到共同问题,这篇文章,笔者结合自己的一些 ...

  10. 2022,前端应该阅读这些文章

    同学们都知道,前端圈变得越来越卷了,各种技术层出不穷,简直让人应接不暇.可能很多跟我一样,一时间,看到这个也想学,看到那个也想学,最终的结果是什么?那就是:啥都没学! 所以笔者花费了几天时间,整理了一 ...

最新文章

  1. awk,sed,grep运用正则与扩展正则
  2. 浅谈Volatile与多线程
  3. Opencms安装和配置
  4. 非计算机专业教学改革,非计算机专业算法分析与设计教学改革论文
  5. 年青人应知道的几个故事
  6. 批量生成多个账户并设置密码
  7. 俄文化部长称Netflix是美国文化侵掠的工具,将占领每台电视机
  8. 博客园文章中图片太大显示不全的解决办法
  9. Linux 入门必备命令
  10. Synology-群晖(一)移动大内网使用 IPv6 + DDNS 实现公网访问
  11. android的短信发送全过程源代码分析
  12. 一本书出版社拿多少,作者拿多少?书的成本几何?出版一本书出版社到底能赚多少钱?(转)...
  13. 薅羊毛拼团商城2.5.3小程序源码
  14. SurroundDepth:自监督多摄像头环视深度估计
  15. jieba textrank关键词提取 python_五款中文分词工具在线PK: Jieba, SnowNLP, PkuSeg,THULAC, HanLP...
  16. Git配置指南与使用
  17. 3月第三周全球五大顶级域名总量新增11.4万个
  18. 基于OHCI的USB主机——UFI读容量命令(ReadCapacity)
  19. 操作系统实验三进程间通信
  20. 856计算机专业综合考试,2017年中央民族大学856计算机学科专业综合硕士研究生考试大纲...

热门文章

  1. 《Ray Tracing in One Weekend》——Chapter 6: Antialiasing
  2. 怎么把截屏的一部分内容涂掉_电脑怎么录屏?录屏软件的使用技巧
  3. 大数据分析需掌握哪些方面
  4. mysql 字符串某个位置_mysql 定位字符串的位置
  5. c语言取字节高四位低四位,C语言取一个数的最高位
  6. DataSet/DataFrame性能比RDD高?
  7. 几维安全:千锤百炼,锻造移动游戏安全防护黄金铠甲
  8. Chalubo僵尸网络来袭 IOT设备或将受到DDoS攻击
  9. CentOS 7.5 编译安装 Nginx 1.15.3
  10. (转)SQL Server数据库状态监控 - 作业状态