nextTick 的使用和原理(面试题)
答题思路:
- nextTick 是做什么的?
- 为什么需要它?
- 开发时什么时候使用?
- 介绍一下如何使用nextTick
- 原理解读,结合异步更新和nextTick生效方式
1. nextTick是做什么的?
nextTick是等待下一次DOM更新刷新的工具方法。
<script>
import { nextTick } from 'vue'export default {data() {return {count: 0}},methods: {async increment() {this.count++// DOM 还未更新console.log(document.getElementById('counter').textContent) // 0await nextTick()// DOM 此时已经更新console.log(document.getElementById('counter').textContent) // 1}}
}
</script><template><button id="counter" @click="increment">{{ count }}</button>
</template>
2. 为什么需要它?
Vue 有个异步更新策略,意思是如果数据变化,Vue不会立刻更新DOM,而是开启一个队列,把组件更新函数保存在队列中,在同一事件循环中发生的所有数据变更会异步的批量更新。这一策略导致我们对数据的修改不会立刻体现在DOM上,此时如果想要获取更新后的DOM状态,就需要使用nextTick。
3. 开发时什么时候使用?
-
created中想要获取DOM时
-
响应式数据变化后获取DOM更新后的状态,比如希望获取列表更新后的高度
4. 介绍一下如何使用nextTick
function nextTick(callback?: () => void): Promise<void>
所以我们只需要在传入的回调函数中访问最新DOM状态即可,或者我们可以await nextTick()方法返回的Promise之后做这件事。
5. 原理解读,结合异步更新和nextTick生效方式
在Vue内部,nextTick之所以能够让我们看到DOM更新后的结果,是因为我们传入的callback会被添加到列队刷新函数(flushSchedulerQueue)的后面,这样等队列内部的更新函数都执行完毕,所有DOM操作也就结束了,callback自然能够获取到最新的DOM值。
将传入的回调函数包装成异步任务,异步任务又分微任务和宏任务,为了尽快执行所以优先选择微任务;
nextTick 提供了四种异步方法 Promise.then、MutationObserver、setImmediate、setTimeout(fn,0)
出于兼容性考虑,依次判断浏览器是否支持,选择使用对应api
优先选择微任务,如果微任务都不支持,则选择宏任务
抛弃了兼容性,直接使用Promise,来实现nextTick
由nextTick的源码可以看出,nextTick本质就是创建了一个微任务(不考虑setTimeout),将其回调推入微任务队列。vue中一个事件循环中的所有dom更新操作也是一个微任务,两者属于同一优先级,执行先后只于入队的先后有关,换句话说,如果你先写了nextTick,再写赋值语句(在此之前没有触发dom更新的操作),那在nextTick中获取的可就不是更新后的dom了
<template><div class="demo"><p class="name">{{ name }}</p><button @click="modify">修改</button></div>
</template>
<script lang="ts" setup>
const name = ref("111");const modify = () => {name.value = "222"; // 关键的赋值语句,如果注释掉,结果就大不一样了nextTick(() => {const text = document.querySelector<HTMLElement>(".name").innerText;console.log(text);});name.value = "333";
};
</script>
如上代码,如果注释掉name.value = “2222”,虽然nextTick语句下面也有赋值操作:name.value = “3333”;,但由于nextTick先进入微任务队列,所以回调先于dom更新执行,所以是获取的dom仍旧是旧的更新前的dom
- 源码补充
import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'// 上面三行与核心代码关系不大,了解即可
// noop 表示一个无操作空函数,用作函数默认值,防止传入 undefined 导致报错
// handleError 错误处理函数
// isIE, isIOS, isNative 环境判断函数,
// isNative 判断某个属性或方法是否原生支持,如果不支持或通过第三方实现支持都会返回 falseexport let isUsingMicroTask = false // 标记 nextTick 最终是否以微任务执行const callbacks = [] // 存放调用 nextTick 时传入的回调函数
let pending = false // 标记是否已经向任务队列中添加了一个任务,如果已经添加了就不能再添加了// 当向任务队列中添加了任务时,将 pending 置为 true,当任务被执行时将 pending 置为 false// // 声明 nextTick 函数,接收一个回调函数和一个执行上下文作为参数
// 回调的 this 自动绑定到调用它的实例上
export function nextTick(cb?: Function, ctx?: Object) {let _resolve// 将传入的回调函数存放到数组中,后面会遍历执行其中的回调callbacks.push(() => {if (cb) { // 对传入的回调进行 try catch 错误捕获try {cb.call(ctx)} catch (e) { // 进行统一的错误处理handleError(e, ctx, 'nextTick')}} else if (_resolve) {_resolve(ctx)}})// 如果当前没有在 pending 的回调,// 就执行 timeFunc 函数选择当前环境优先支持的异步方法if (!pending) {pending = truetimerFunc()}// 如果没有传入回调,并且当前环境支持 promise,就返回一个 promise// 在返回的这个 promise.then 中 DOM 已经更新好了,if (!cb && typeof Promise !== 'undefined') {return new Promise(resolve => {_resolve = resolve})}
}// 判断当前环境优先支持的异步方法,优先选择微任务
// 优先级:Promise---> MutationObserver---> setImmediate---> setTimeout
// setTimeout 可能产生一个 4ms 的延迟,而 setImmediate 会在主线程执行完后立刻执行
// setImmediate 在 IE10 和 node 中支持// 当在同一轮事件循环中多次调用 nextTick 时 ,timerFunc 只会执行一次let timerFunc
// 判断当前环境是否原生支持 promise
if (typeof Promise !== 'undefined' && isNative(Promise)) { // 支持 promiseconst p = Promise.resolve()timerFunc = () => {// 用 promise.then 把 flushCallbacks 函数包裹成一个异步微任务p.then(flushCallbacks)if (isIOS) setTimeout(noop)// 这里的 setTimeout 是用来强制刷新微任务队列的// 因为在 ios 下 promise.then 后面没有宏任务的话,微任务队列不会刷新}// 标记当前 nextTick 使用的微任务isUsingMicroTask = true// 如果不支持 promise,就判断是否支持 MutationObserver// 不是IE环境,并且原生支持 MutationObserver,那也是一个微任务
} else if (!isIE && typeof MutationObserver !== 'undefined' && (isNative(MutationObserver) ||MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {let counter = 1// new 一个 MutationObserver 类const observer = new MutationObserver(flushCallbacks) // 创建一个文本节点const textNode = document.createTextNode(String(counter)) // 监听这个文本节点,当数据发生变化就执行 flushCallbacks observer.observe(textNode, { characterData: true })timerFunc = () => {counter = (counter + 1) % 2textNode.data = String(counter) // 数据更新}isUsingMicroTask = true // 标记当前 nextTick 使用的微任务// 判断当前环境是否原生支持 setImmediate
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {timerFunc = () => { setImmediate(flushCallbacks) }
} else {// 以上三种都不支持就选择 setTimeouttimerFunc = () => { setTimeout(flushCallbacks, 0) }
}// 如果多次调用 nextTick,会依次执行上面的方法,将 nextTick 的回调放在 callbacks 数组中
// 最后通过 flushCallbacks 函数遍历 callbacks 数组的拷贝并执行其中的回调
function flushCallbacks() {pending = false const copies = callbacks.slice(0) // 拷贝一份 callbackscallbacks.length = 0 // 清空 callbacksfor (let i = 0; i < copies.length; i++) { // 遍历执行传入的回调copies[i]()}
}// 为什么要拷贝一份 callbacks// 用 callbacks.slice(0) 将 callbacks 拷贝出来一份,
// 是因为考虑到在 nextTick 回调中可能还会调用 nextTick 的情况,
// 如果在 nextTick 回调中又调用了一次 nextTick,则又会向 callbacks 中添加回调,
// 而 nextTick 回调中的 nextTick 应该放在下一轮执行,
// 否则就可能出现一直循环的情况,
// 所以需要将 callbacks 复制一份出来然后清空,再遍历备份列表执行回调
相关文章:
nextTick 的使用和原理(面试题)
答题思路: nextTick 是做什么的?为什么需要它?开发时什么时候使用?介绍一下如何使用nextTick原理解读,结合异步更新和nextTick生效方式 1. nextTick是做什么的? nextTick是等待下一次DOM更新刷新的工具方法…...
Hudi系列19:Hudi写入模式
一. Changelog 模式 如果希望 Hoodie 保留消息的所有变更(I/-U/U/D), 之后接上 Flink 引擎的有状态计算实现全链路近实时数仓(增量计算), Hoodie 的 MOR 表通过行存 原生支持 保留消息的所有变更(format 层面的集成), 通过流读MOR 表可以消费到所有的变…...
Kubernetes安全
Kubernetes RBAC授权 Kubernetes 安全框架 K8S安全控制框架主要由下面3个阶段进行控制,每一个阶段都支持插件方式,通过API Server配置来启用插件。1. Authentication(鉴权) K8s Apiserver提供三种客户端身份认证:• H…...
全国进入裁员潮,到底是大厂难混?还是我技不如人?
前言 面对裁员,每个人的心态不同。他们有的完全没有料想到自己会被裁,有的却对裁员之事早有准备。大多数人,我想是焦虑失落的吧。 01 “降本增效”,HR怒提裁员刀 小默 | 32岁 芯片行业 人力资源 1月份,身处芯片行业H…...
电子技术——内部电容效应以及MOS与BJT的高频响应模型
电子技术——内部电容效应以及MOS与BJT的高频响应模型 耦合和旁路电容决定了放大器的低频响应,同时内部电容效应决定了放大器的高频响应。本节,我们简单简单介绍一下内部电容效应,并且更重要的是如何在小信号模型中模型化内部电容效应。 MOS…...
华为OD机试题 - 出租车计费(JavaScript)
最近更新的博客 2023新华为OD机试题 - 斗地主(JavaScript)2023新华为OD机试题 - 箱子之形摆放(JavaScript)2023新华为OD机试题 - 考古学家(JavaScript)2023新华为OD机试题 - 相同数字的积木游戏 1(JavaScript)2023新华为OD机试题 - 最多等和不相交连续子序列(JavaScri…...
Django框架进阶版
一、Django介绍 1.起源 2005年发布,采用python语言编写的。 早期Django主要做新闻和内容管理 重量级python web框架,配备了大量组件 2.组件 包含组件如下 基本配置文件/路由系统 MTV设计模式 Cookies和Session 分页和发邮件 Admin管理后台 3…...
2023美赛F题全部代码+数据+结果 数学建模
2023年美赛F题全部思路 数据代码都已完成 全部内容见链接:https://www.jdmm.cc/file/2708700/ 1.根据文献选的GGDP的指标,发现GGDP与水资源等有关,由此可以筛选出影响GGDP的所有因子,并可以用所有因子利用层次分析法建立评价体…...
Java基础-logback日志使用
日志 1.1 作用: 跟输出语句一样,可以把程序在运行过程中的详细信息都打印在控制台上。 利用log日志还可以把这些详细信息保存到文件和数据库中。 1.2 使用步骤: 不是java的,也不是自己写的,是第三方提供…...
kaggle竞赛-宠物受欢迎程度(赛题讲解与数据分析)
比赛官网地址 赛题介绍 petfinder是马来西亚领先的动物福利平台宠物网站地址 该网站使用可爱指数来排名宠物照片。它分析了图片组成和其他因素,并与数千个宠物档案的表现进行了比较。 在这场比赛中,你将分析原始图像和元数据来预测宠物照片的“Pawp…...
Go语言基础知识学习笔记
环境准备 下载安装Golang:https://golang.google.cn/dl/ 因为国外下载速度较慢,我们需要配置国内代理 # 开启包管理工具 go env -w GO111MODULEon # 设置代理 go env -w GOPROXYhttps://goproxy.cn,direct # 设置不走 proxy 的私有仓库,多…...
Python3 错误和异常
Python3 错误和异常 作为 Python 初学者,在刚学习 Python 编程时,经常会看到一些报错信息,在前面我们没有提及,这章节我们会专门介绍。 Python 有两种错误很容易辨认:语法错误和异常。 Python assert(断…...
程序人生 - 学习和分享
文章目录记于 230217学习安排泛学AI 和 未来记于 230217 刚入行时,经常看到技术博客中,博主们分享生活,比如相亲、上班生活,甚至还有人发结婚照。这个栏目通常被称为:程序人生。 这个现象已经很久没看到了,…...
基于树莓派的智能家居项目整理
一、功能介绍 二、设计框图 三、实物展示 四、程序 一、功能介绍硬件:树莓派3B、LD3320语音识别模块、pi 摄像头、继电器组、小灯、火焰传感器、蜂鸣器、电 磁锁 项目框架: 采用了简单工厂模式的一个设计方式。稳定,拓展性…...
《洛阳冬冷》
——洛阳的冬天太冷,最暖不过你的眼神。 ******* 她拿了个画着几丛竹子的小团扇子一路分花拂柳地往前走,后面一水儿的侍女不敢出声,只得地默默跟着她。她一张脸本来生得就好看,这一怒起来竟然还更加的好看了。此时她走得太急&…...
YOLOv5简介
YOLOv5 一、输入端 1. Mosaic数据增强: CutMix 数据增强:随机生成一个裁剪框Box,裁剪掉A图中的相应位置,然后用B图相应位置的ROI放到A中被裁剪的区域中形成新的样本。采用加权求和的方式计算损失,将A区域中被cut掉的…...
【面向对象语言三大特性之 “继承”】
目录 1.继承的概念及定义 1.1继承的概念 1.2 继承定义 1.2.1定义格式 1.2.2继承关系和访问限定符 1.2.3继承基类成员访问方式的变化 2.基类和派生类对象赋值转换 3.继承中的作用域 4.派生类的默认成员函数 5.继承与友元 6. 继承与静态成员 7.复杂的菱形继承及菱形虚拟…...
Ambari2.7.5集群搭建详细流程
0 说明 本文基于本地虚拟机从零开始搭建ambari集群 1 前置条件 1.1 本地虚拟机环境 节点角色ambari-1ambari-server ambari-agentambari-2ambari-agentambari-3ambari-agent 1.2 安装包 1.3 修改主机名并配置hosts文件 hostnamectl set-hostname ambari-1 hostnamectl se…...
房产|1月全国70城房价出炉!疫情放开后你关心的城市房价有何变化
2023年1月份,70个大中城市中新房销售价格环比上涨城市个数增加;一线城市新房销售价格环比同比转涨、二三线城市环比降势趋缓,二三线城市同比下降。 | 新房/二手房12月-1月环比上涨城市数量变化 70个大中城市中,新房环比上涨城市…...
秒验 重新定义“一键登录”
现如今,一般APP在注册登录时,仍然要经历填写用户名、密码、绑定手机号等一系列传统流程,有的人认为可以通过第三方登录避免这些流程,但仍旧要经历手机验证码的环节,而且存在验证码被拦截的风险,短信费用也很…...
ZenBuster:一款功能强大的多线程跨平台URL枚举工具
关于ZenBuster ZenBuster是一款功能强大的多线程跨平台URL枚举工具,该工具基于Python开发,同时还具备暴力破解功能。 该工具适用于安全专业人员,可以在渗透测试或CTF比赛中为广大研究人员提供帮助,并收集和目标相关的各种信息。…...
2023年美赛ICM问题E:光污染 这题很好做啊!
2023年美赛ICM问题E:光污染 这题很好做啊!![在这里插入图片描述](https://img-blog.csdnimg.cn/e918cc6fc9214b53bf4859063bfe56b0.png#pic_center) 我看到DS数模的分析,看似头头是道,实则GouPi不通,我出一个,用于大家…...
InVEST模型 | 01 InVEST模型安装(Windows10)
除了在Python Anaconda环境中进行安装InVEST模型Python安装,平时最常使用的安装方式是通过.exe直接进行安装,本节介绍的就是直接下载安装的步骤: 打开InVEST模型下载页面 链接为:https://naturalcapitalproject.stanford.edu/…...
spring-web InvocableHandlerMethod 源码分析
说明 本文基于 jdk 8, spring-framework 5.2.x 编写。author JellyfishMIX - github / blog.jellyfishmix.comLICENSE GPL-2.0 类层次 HandlerMethod,处理器的方法的封装对象。HandlerMethod 只提供了处理器的方法的基本信息,不提供调用逻辑。 Invoca…...
一分钟了解微信公众号服务器配置自动回复
1、建一个web服务工程 2、开放任意一个接口, 比如 /aaa/bbb/ccc 把接口路径配置在这里,ip为公网ip或域名,其他的参数默认,对入门选手没啥用 3、该接口允许get和post两种方式访问,接口需要对于访问方式编写两套逻辑…...
打印不同的图形-课后程序(JAVA基础案例教程-黑马程序员编著-第四章-课后作业)
【案例4-1】打印不同的图形 记得 关注,收藏,评论哦,作者将持续更新。。。。 【案例介绍】 案例描述 本案例要求编写一个程序,可以根据用户要求在控制台打印出不同的图形。例如,用户自定义半径的圆形和用户自定义边长的…...
14. QT_OPenGL中引入顶点着色器和片段着色器
1. 说明: 着色器是OPenGL中非常重要的一部分,在有了模型后,如果未给模型添加着色器,那么渲染效果会折扣很多。着色器中使用到的语言是GLSL(OPenGL Shader Language),可以通过这篇文章GLSL基本语法进行了解。 效果展示:…...
ecaozzz
2. 图形报表ECharts 2.1 ECharts简介 ECharts缩写来自Enterprise Charts,商业级数据图表,是百度的一个开源的使用JavaScript实现的数据可视化工具,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/…...
应用部署初探:6个保障安全的最佳实践
在之前的文章中,我们了解了应用部署的阶段以及常见的部署模式,包括微服务架构的应用应该如何部署等基本内容。本篇文章将介绍如何安全地部署应用程序。 安全是软件开发生命周期(SDLC)中的关键部分,同时也需要成为 S…...
转转测试环境docker化实践
测试环境对于任何一个软件公司来讲,都是核心基础组件之一。转转的测试环境伴随着转转的发展也从单一的几套环境发展成现在的任意的docker动态环境docker稳定环境环境体系。期间环境系统不断的演进,去适应转转集群扩张、新业务的扩展,走了一些…...
做平台网站怎么做的/建站abc
实现以下的add()的方法 output()时打印前面的参数之和 add(1,2).add(3).add(4).output()function add(...args){return [...args] } Array.prototype.add function(...args){this.push(...args)return this } Array.prototype.output function(){return this.reduce((a,b)&g…...
网站建设论文伯乐在线/公众号推广引流
2019独角兽企业重金招聘Python工程师标准>>> 对于请求头Content-Type,默认application/x-www-form-urlencoded。 1、(可用) CloseableHttpClient client HttpClients.createDefault(); // 实例化一个post对象 Ht…...
做的网站必须放在idc机房吗/合肥seo服务商
最近在做一个类似与任务管理器的东西,里面有个功能,可以通过这个管理器结束掉其他的进程。在Android平台下,结束进程的方法还是比较多的。首先指明,此处的“结束进程”,包含了结束自身进程和结束其他进程两个方面。通过…...
海门市住房和城乡建设局网站/营销方案策划书
bug1:while循环中的*des *src; 不能这么写吧。。。 bug2:maxSize没有定义 暂时看到这么多转载于:https://www.cnblogs.com/yuanyue-nenu/p/7702004.html...
网站建设的目的及功能/在线一键生成网页
JackChen1024 关注 2017.03.12 14:06* 字数 11049 阅读 915评论 1喜欢 61Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。本系列教程将有助于你学习和理解Java NIO。 Java NIO提供了与标准IO不同的IO…...
wordpress阿里云图片/搜索引擎推广的常见形式有
https://gitee.com/shenzhanwang/Spring-activiti...