vue基础知识十三:Vue中的$nextTick有什么作用?

news2024/11/26 3:47:33

在这里插入图片描述
一、NextTick是什么

官方对其的定义

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

什么意思呢?

我们可以理解成,Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新

举例一下

Html结构

{{ message }}

构建一个vue实例

const vm = new Vue({
  el: '#app',
  data: {
    message: '原始值'
  }
})

修改message

this.message = '修改后的值1'
this.message = '修改后的值2'
this.message = '修改后的值3'

这时候想获取页面最新的DOM节点,却发现获取到的是旧值

console.log(vm.$el.textContent) // 原始值

这是因为message数据在发现变化的时候,vue并不会立刻去更新Dom,而是将修改数据的操作放在了一个异步操作队列中

如果我们一直修改相同数据,异步操作队列还会进行去重

等待同一事件循环中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行DOM的更新

为什么要有nexttick

举个例子

{{num}}
for(let i=0; i<100000; i++){
    num = i
}

如果没有 nextTick 更新机制,那么 num 每次更新值都会触发视图更新(上面这段代码也就是会更新10万次视图),有了nextTick机制,只需要更新一次,所以nextTick本质是一种优化策略

二、使用场景

如果想要在修改数据后立刻得到更新后的DOM结构,可以使用Vue.nextTick()

第一个参数为:回调函数(可以获取最近的DOM结构)

第二个参数为:执行函数上下文

// 修改数据
vm.message = '修改后的值'
// DOM 还没有更新
console.log(vm.$el.textContent) // 原始的值
Vue.nextTick(function () {
  // DOM 更新了
  console.log(vm.$el.textContent) // 修改后的值
})

组件内使用 vm. n e x t T i c k ( ) 实例方法只需要通过 t h i s . nextTick() 实例方法只需要通过this. nextTick()实例方法只需要通过this.nextTick(),并且回调函数中的 this 将自动绑定到当前的 Vue 实例上

this.message = '修改后的值'
console.log(this.$el.textContent) // => '原始的值'
this.$nextTick(function () {
    console.log(this.$el.textContent) // => '修改后的值'
})

三、实现原理

源码位置:/src/core/util/next-tick.js

callbacks也就是异步操作队列

callbacks新增回调函数后又执行了timerFunc函数,pending是用来标识同一个时间只能执行一次

export function nextTick(cb?: Function, ctx?: Object) {
  let _resolve;

  // cb 回调函数会经统一处理压入 callbacks 数组
  callbacks.push(() => {
    if (cb) {
      // 给 cb 回调函数执行加上了 try-catch 错误处理
      try {
        cb.call(ctx);
      } catch (e) {
        handleError(e, ctx, 'nextTick');
      }
    } else if (_resolve) {
      _resolve(ctx);
    }
  });

  // 执行异步延迟函数 timerFunc
  if (!pending) {
    pending = true;
    timerFunc();
  }

  // 当 nextTick 没有传入函数参数的时候,返回一个 Promise 化的调用
  if (!cb && typeof Promise !== 'undefined') {
    return new Promise(resolve => {
      _resolve = resolve;
    });
  }
}

timerFunc函数定义,这里是根据当前环境支持什么方法则确定调用哪个,分别有:

Promise.then、MutationObserver、setImmediate、setTimeout

通过上面任意一种方法,进行降级操作

export let isUsingMicroTask = false
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  //判断1:是否原生支持Promise
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks)
    if (isIOS) setTimeout(noop)
  }
  isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
  isNative(MutationObserver) ||
  MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
  //判断2:是否原生支持MutationObserver
  let counter = 1
  const observer = new MutationObserver(flushCallbacks)
  const textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {
    characterData: true
  })
  timerFunc = () => {
    counter = (counter + 1) % 2
    textNode.data = String(counter)
  }
  isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  //判断3:是否原生支持setImmediate
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  //判断4:上面都不行,直接用setTimeout
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}

无论是微任务还是宏任务,都会放到flushCallbacks使用

这里将callbacks里面的函数复制一份,同时callbacks置空

依次执行callbacks里面的函数

function flushCallbacks () {
  pending = false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (let i = 0; i < copies.length; i++) {
    copies[i]()
  }
}

小结:

  • 把回调函数放入callbacks等待执行
  • 将执行函数放到微任务或者宏任务中
  • 事件循环到了微任务或者宏任务,执行函数依次执行callbacks中的回调

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1020215.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里测试岗:惨不忍睹的三面,幸好做足了准备,月薪17k,已拿offer....

我今年25岁&#xff0c;专业是电子信息工程本科&#xff0c;19年年末的时候去面试&#xff0c;统一投了测试的岗位&#xff0c;软件硬件都有&#xff0c;那时候面试的两家公司都是做培训的&#xff0c;当初没啥钱&#xff0c;他们以面试为谎言再推荐去培训这点让我特别难受。 …

开启编程之门

自我介绍 目前已经大二了&#xff0c;计算机专业在读&#xff0c;是一个热爱编程&#xff0c;做事踏实专注的人。转眼间一年已经过去了&#xff0c;也接触编程一年了&#xff0c;但开始并没有对所学所想进行很好的总结和输出&#xff0c;这一年也有了新的很多感悟与心得&#x…

JVM——5.类文件结构

这篇文章我们来讲一下jvm的类文件结构 目录 1.引言 2.类文件结构概论 3.魔数与class文件的版本 4.常量池 5.访问标志 6.类索引、父类索引与接口索引集合 7.字段表集合 8.方法表集合 9.属性表集合 9.1code属性 9.2 Exception属性 10小结 1.引言 代码编译的结果从本…

vue学习-02vue入门之组件

删除Vue-cli预设 在用户根目录下(C:\Users\你的用户名)这个地址里有一个.vuerc 文件,修改或删除配置 组件 Props(组件之间的数据传递) Prop 的大小写 (camelCase vs kebab-case)不敏感Prop 类型: String Number Boolean Array Object Date Function Symbol传递静态或动态 Pr…

「聊设计模式」之抽象工厂模式(Abstract Factory)

&#x1f3c6;本文收录于《聊设计模式》专栏&#xff0c;专门攻坚指数级提升&#xff0c;助你一臂之力&#xff0c;带你早日登顶&#x1f680;&#xff0c;欢迎持续关注&&收藏&&订阅&#xff01; 前言 在软件开发中&#xff0c;设计模式是一种被广泛使用的经验…

kudu 1.4.0 离线安装

1.准备rpm安装包 kudu-1.4.0: kudu的基础安装包 kudu-client0-1.4.0: kudu的c++客户端共享库 kudu-client-devel-1.4.0: kudu的c++客户端共享库sdk kudu-master-1.4.0: kudu master kudu-tserver-1.4.0: kudu tserver

任意输入一个整数m,若m不是素数,则对m进行质因数分解,并以质因数从小到大顺序排列的乘积形式输出

每个合数都可以写成几个质数&#xff08;也可称为素数&#xff09;相乘的形式 &#xff0c;这几个质数就都叫做这个合数的质因数。 #include <stdio.h> int isPrime(int num)// 判断一个数是否是素数 {if (num < 2) {return 0;}for (int i 2; i * i < num; i) {…

汽车电子 -- CAN总线波特率计算方法

上一篇文章介绍 PCAN View 安装与使用 的时候&#xff0c;留下了两个问题&#xff0c;CAN总线波特率该怎么计算&#xff1f; 下图里的这些 Prescaler、tseg1、tseg2、sync Jump Width是什么意思&#xff1f; CAN2.0协议中定义标称位速率为一理想的发送器在没有重新同步的情况…

2023年毫米波行业研究报告

第一章 行业概况 1.1 定义 毫米波是一种电磁波&#xff0c;其波长范围在1毫米至10毫米之间&#xff0c;频率介于30GHz至300GHz。与sub-6G (6GHz以下频段&#xff09;的5G系统相比&#xff0c;5G毫米波通信在带宽、时延和灵活弹性空口配置方面具有明显优势。这使其能够有效地满…

风车时间锁管理 - 构建IPA文件加锁+签名+管理一站式解决方案

时间锁管理&#xff1a;是一种用于控制对某些资源、功能或操作的访问权限的机制&#xff0c;它通过设定时间限制来限制对特定内容、系统或功能的访问或执行&#xff0c;以提高安全性和控制性&#xff0c;时间锁管理常见于以下场景&#xff1a; 1. 文件或文档的保密性&#xff…

STL list

文章目录 一、list 类的模拟实现 list 是一个带头双向循环链表&#xff0c;可以存储任意类型 模板参数 T 表示存储元素的类型&#xff0c;Alloc 是空间配置器&#xff0c;一般不用传 一、list 类的模拟实现 iterator 和 const_iterator 除了下述不同外&#xff0c;其他代码基…

优优嗨聚集团:抖音外卖转为区域代理,美团外卖是否胜利

在外卖市场日益激烈的竞争中&#xff0c;抖音和美团两大巨头都有着不同的策略。近期&#xff0c;抖音外卖宣布转为区域代理模式&#xff0c;而美团外卖则持续扩大市场份额。 外卖市场近年来呈现出爆炸性增长&#xff0c;成为消费者日常生活中不可或缺的一部分。根据艾媒咨询数据…

Unity之手游UI的点击和方向移动

一 Button的点击 1.1 新建UI -> Button 1.2 在Button上面右击添加空物体 1.3 创建脚本挂载到空物体上面 脚本内容添加点击方法&#xff0c;来控制物体的显示隐藏 using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using Unit…

Keepalived+LVS负载均衡

Keepalived 是一个用于实现高可用性的开源软件&#xff0c;它基于 VRRP&#xff08;Virtual Router Redundancy Protocol&#xff09;协议&#xff0c;允许多台服务器协同工作&#xff0c;以确保在某个服务器出现故障时服务的连续性。Keepalived 的核心思想是将多台服务器配置成…

剑指offer(C++)-JZ67:把字符串转换成整数atoi(算法-模拟)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 写一个函数 StrToInt&#xff0c;实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。…

8种LED显示屏的安装方式

LED显示屏可以根据不同的应用需求和场地条件采用多种安装方式。 LED显示屏的常见安装方式包括&#xff1a; 立柱式&#xff1a;一般多用于大厦门口、大楼大厅等户外场所&#xff0c;可以抵抗风雨侵蚀&#xff0c;更适用于户外广告牌的使用。安装方式有单立柱安装、双立柱安装和…

联合matlab和Arcgis进行netcdf格式的雪覆盖数据的重新投影栅格

图片摘要 本专栏目的是将netcdf格式的雪覆盖数据进行重新投影&#xff0c;需要使用的工具包括matlab和Arcgis&#xff0c;下面进入正题。 1.数据的下载与读取---matlab 最近我需要读取北半球的冰雪覆盖数据&#xff0c;下载的是MODIS/Terra Snow Cover Monthly L3 Global 0.0…

CPU的各种存储器接口

设计电路时往往绕不开要做一些内存或者外存的接口设计&#xff0c;比如接SDRAM、NAND FLASH等等。这些无非是为了扩展原来CPU的内存或者外存资源&#xff0c;方便运行更大的系统。比较常见的就是一些Linux的核心板。I.MX6这个就是很多产品设计中使用的。 那么&#xff0c;在这些…

uniapp 可输入可选择的........框

安装 uniapp: uni-combox地址 vue页面 <uni-combox :border"false" input"selectname" focus"handleFocus" blur"handleBlur" :candidates"candidates" placeholder"请选择姓名" v-model"name"&g…

基于JAVA+SpringBoot+Vue+协同过滤算法+爬虫的前后端分离的租房系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 随着城市化进程的加快…