当前位置: 首页 > news >正文

nextTick 的使用和原理(面试题)

答题思路:

  1. nextTick 是做什么的?
  2. 为什么需要它?
  3. 开发时什么时候使用?
  4. 介绍一下如何使用nextTick
  5. 原理解读,结合异步更新和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. 开发时什么时候使用?

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)

  • vue2

出于兼容性考虑,依次判断浏览器是否支持,选择使用对应api
在这里插入图片描述
优先选择微任务,如果微任务都不支持,则选择宏任务

  • vue3

抛弃了兼容性,直接使用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 的使用和原理(面试题)

答题思路&#xff1a; nextTick 是做什么的&#xff1f;为什么需要它&#xff1f;开发时什么时候使用&#xff1f;介绍一下如何使用nextTick原理解读&#xff0c;结合异步更新和nextTick生效方式 1. nextTick是做什么的&#xff1f; nextTick是等待下一次DOM更新刷新的工具方法…...

Hudi系列19:Hudi写入模式

一. Changelog 模式 如果希望 Hoodie 保留消息的所有变更(I/-U/U/D), 之后接上 Flink 引擎的有状态计算实现全链路近实时数仓(增量计算)&#xff0c; Hoodie 的 MOR 表通过行存 原生支持 保留消息的所有变更(format 层面的集成)&#xff0c; 通过流读MOR 表可以消费到所有的变…...

Kubernetes安全

Kubernetes RBAC授权 Kubernetes 安全框架 K8S安全控制框架主要由下面3个阶段进行控制&#xff0c;每一个阶段都支持插件方式&#xff0c;通过API Server配置来启用插件。1. Authentication&#xff08;鉴权&#xff09; K8s Apiserver提供三种客户端身份认证&#xff1a;• H…...

全国进入裁员潮,到底是大厂难混?还是我技不如人?

前言 面对裁员&#xff0c;每个人的心态不同。他们有的完全没有料想到自己会被裁&#xff0c;有的却对裁员之事早有准备。大多数人&#xff0c;我想是焦虑失落的吧。 01 “降本增效”&#xff0c;HR怒提裁员刀 小默 | 32岁 芯片行业 人力资源 1月份&#xff0c;身处芯片行业H…...

电子技术——内部电容效应以及MOS与BJT的高频响应模型

电子技术——内部电容效应以及MOS与BJT的高频响应模型 耦合和旁路电容决定了放大器的低频响应&#xff0c;同时内部电容效应决定了放大器的高频响应。本节&#xff0c;我们简单简单介绍一下内部电容效应&#xff0c;并且更重要的是如何在小信号模型中模型化内部电容效应。 MOS…...

华为OD机试题 - 出租车计费(JavaScript)

最近更新的博客 2023新华为OD机试题 - 斗地主(JavaScript)2023新华为OD机试题 - 箱子之形摆放(JavaScript)2023新华为OD机试题 - 考古学家(JavaScript)2023新华为OD机试题 - 相同数字的积木游戏 1(JavaScript)2023新华为OD机试题 - 最多等和不相交连续子序列(JavaScri…...

Django框架进阶版

一、Django介绍 1.起源 2005年发布&#xff0c;采用python语言编写的。 早期Django主要做新闻和内容管理 重量级python web框架&#xff0c;配备了大量组件 2.组件 包含组件如下 基本配置文件/路由系统 MTV设计模式 Cookies和Session 分页和发邮件 Admin管理后台 3…...

2023美赛F题全部代码+数据+结果 数学建模

2023年美赛F题全部思路 数据代码都已完成 全部内容见链接&#xff1a;https://www.jdmm.cc/file/2708700/ 1.根据文献选的GGDP的指标&#xff0c;发现GGDP与水资源等有关&#xff0c;由此可以筛选出影响GGDP的所有因子&#xff0c;并可以用所有因子利用层次分析法建立评价体…...

Java基础-logback日志使用

日志 1.1 作用&#xff1a; ​ 跟输出语句一样&#xff0c;可以把程序在运行过程中的详细信息都打印在控制台上。 ​ 利用log日志还可以把这些详细信息保存到文件和数据库中。 1.2 使用步骤&#xff1a; ​ 不是java的&#xff0c;也不是自己写的&#xff0c;是第三方提供…...

kaggle竞赛-宠物受欢迎程度(赛题讲解与数据分析)

比赛官网地址 赛题介绍 petfinder是马来西亚领先的动物福利平台宠物网站地址 该网站使用可爱指数来排名宠物照片。它分析了图片组成和其他因素&#xff0c;并与数千个宠物档案的表现进行了比较。 在这场比赛中&#xff0c;你将分析原始图像和元数据来预测宠物照片的“Pawp…...

Go语言基础知识学习笔记

环境准备 下载安装Golang&#xff1a;https://golang.google.cn/dl/ 因为国外下载速度较慢&#xff0c;我们需要配置国内代理 # 开启包管理工具 go env -w GO111MODULEon # 设置代理 go env -w GOPROXYhttps://goproxy.cn,direct # 设置不走 proxy 的私有仓库&#xff0c;多…...

Python3 错误和异常

Python3 错误和异常 作为 Python 初学者&#xff0c;在刚学习 Python 编程时&#xff0c;经常会看到一些报错信息&#xff0c;在前面我们没有提及&#xff0c;这章节我们会专门介绍。 Python 有两种错误很容易辨认&#xff1a;语法错误和异常。 Python assert&#xff08;断…...

程序人生 - 学习和分享

文章目录记于 230217学习安排泛学AI 和 未来记于 230217 刚入行时&#xff0c;经常看到技术博客中&#xff0c;博主们分享生活&#xff0c;比如相亲、上班生活&#xff0c;甚至还有人发结婚照。这个栏目通常被称为&#xff1a;程序人生。 这个现象已经很久没看到了&#xff0c…...

基于树莓派的智能家居项目整理

一、功能介绍 二、设计框图 三、实物展示 四、程序 一、功能介绍硬件&#xff1a;树莓派3B、LD3320语音识别模块、pi 摄像头、继电器组、小灯、火焰传感器、蜂鸣器、电 磁锁 项目框架&#xff1a; 采用了简单工厂模式的一个设计方式。稳定&#xff0c;拓展性…...

《洛阳冬冷》

——洛阳的冬天太冷&#xff0c;最暖不过你的眼神。 ******* 她拿了个画着几丛竹子的小团扇子一路分花拂柳地往前走&#xff0c;后面一水儿的侍女不敢出声&#xff0c;只得地默默跟着她。她一张脸本来生得就好看&#xff0c;这一怒起来竟然还更加的好看了。此时她走得太急&…...

YOLOv5简介

YOLOv5 一、输入端 1. Mosaic数据增强&#xff1a; CutMix 数据增强&#xff1a;随机生成一个裁剪框Box&#xff0c;裁剪掉A图中的相应位置&#xff0c;然后用B图相应位置的ROI放到A中被裁剪的区域中形成新的样本。采用加权求和的方式计算损失&#xff0c;将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月份&#xff0c;70个大中城市中新房销售价格环比上涨城市个数增加&#xff1b;一线城市新房销售价格环比同比转涨、二三线城市环比降势趋缓&#xff0c;二三线城市同比下降。 | 新房/二手房12月-1月环比上涨城市数量变化 70个大中城市中&#xff0c;新房环比上涨城市…...

秒验 重新定义“一键登录”

现如今&#xff0c;一般APP在注册登录时&#xff0c;仍然要经历填写用户名、密码、绑定手机号等一系列传统流程&#xff0c;有的人认为可以通过第三方登录避免这些流程&#xff0c;但仍旧要经历手机验证码的环节&#xff0c;而且存在验证码被拦截的风险&#xff0c;短信费用也很…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

Linux部署私有文件管理系统MinIO

最近需要用到一个文件管理服务&#xff0c;但是又不想花钱&#xff0c;所以就想着自己搭建一个&#xff0c;刚好我们用的一个开源框架已经集成了MinIO&#xff0c;所以就选了这个 我这边对文件服务性能要求不是太高&#xff0c;单机版就可以 安装非常简单&#xff0c;几个命令就…...

游戏开发中常见的战斗数值英文缩写对照表

游戏开发中常见的战斗数值英文缩写对照表 基础属性&#xff08;Basic Attributes&#xff09; 缩写英文全称中文释义常见使用场景HPHit Points / Health Points生命值角色生存状态MPMana Points / Magic Points魔法值技能释放资源SPStamina Points体力值动作消耗资源APAction…...

高保真组件库:开关

一:制作关状态 拖入一个矩形作为关闭的底色:44 x 22,填充灰色CCCCCC,圆角23,边框宽度0,文本为”关“,右对齐,边距2,2,6,2,文本颜色白色FFFFFF。 拖拽一个椭圆,尺寸18 x 18,边框为0。3. 全选转为动态面板状态1命名为”关“。 二:制作开状态 复制关状态并命名为”开…...