通俗易懂的Vue异步更新策略及 nextTick 原理

2023-11-17

最近在学习一些底层方面的知识。所以想做个系列尝试去聊聊这些比较复杂又很重要的知识点。学习就好比是座大山,只有自己去登山,才能看到不一样的风景,体会更加深刻。今天我们就来聊聊Vue中比较重要的异步更新策略及 nextTick 原理。

在聊话题之前我们可以看下下面这道面试题:

setTimeout(() => {
  console.log('真的在300ms后打印吗?')
}, 300)
复制代码

这段代码很简单,相信很多人都会说yes。当然也不乏大牛的存在,一眼就能看出答案来不一定。这是为什么呢?在面试过程中碰到这类问题如何回答才能让面试官满意,并且如何去扩散我们的知识点。

在正式讲解之前我们可以先了解一些简单的概念:

什么是进程: 进程是cpu分配资源的最小单位;(是能拥有资源和独立运行的最小单位)

什么是线程: 线程是cpu调度的最小单位;(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)

概念理解起来比较枯燥,做个比喻好了:

进程 就是一个公司,每个公司都有自己的资源可以调度;公司之间是相互独立的;而 线程 就是公司中的每个员工,多个员工一起合作,完成任务,公司可以有一名员工或多个,员工之间共享公司的空间。

浏览器是多进程的: 在浏览器中,每打开一个tab页面,其实就是新开了一个进程,在这个进程中,还有ui渲染线程,js引擎线程,http请求线程等。 所以,浏览器是一个多进程的。

js是单线程的: js是作为浏览器的脚本语言,主要是实现用户与浏览器的交互,以及操作dom;这决定了它只能是单线程,否则会带来很复杂的同步问题。 举个例子:如果js被设计了多线程,如果有一个线程要修改一个dom元素,另一个线程要删除这个dom元素,此时浏览器就会一脸茫然,不知所措。所以,为了避免复杂性,从一诞生,JavaScript就是单线程。

js执行机制--Event loop

由于js是单线程,js设计者把任务分为同步任务和异步任务,同步任务都在主线程上排队执行,前面任务没有执行完成,后面的任务会一直等待;异步任务则是挂在在一个任务队列里,等待主线程所有任务执行完成后,通知任务队列可以把可执行的任务放到主线程执行。异步任务放到主线程执行完后,又通知任务队列把下一个异步任务放到主线程中执行。这个过程一直持续,直到异步任务执行完成,这个持续重复的过程就叫Event loop。而一次循环就是一次tick 。

在任务队列中的异步任务又可以分为两种microtast(微任务) 和 macrotask(宏任务)

microtast(微任务):Promise, process.nextTick, Object.observe, MutationObserver

macrotask(宏任务):script整体代码、setTimeout、 setInterval等

执行优先级上,先执行宏任务macrotask,再执行微任务mincrotask。

执行过程中需要注意的几点是:

  • 在一次event loop中,microtask在这一次循环中是一直取一直取,直到清空microtask队列,而macrotask则是一次循环取一次。
  • 如果执行事件循环的过程中又加入了异步任务,如果是macrotask,则放到macrotask末尾,等待下一轮循环再执行。如果是microtask,则放到本次event loop中的microtask任务末尾继续执行。直到microtask队列清空。

    到这里,上面那个300ms的定时器为什么不一定是精确的300ms之后打印就能理解了:

因为300ms的setTimeout并不是说300ms之后立马执行,而是300ms之后被放入任务列表里面。等待事件循环,等待它执行的时候才能执行代码。如果异步任务列表里面只有它这个macrotask任务,那么就是精确的300ms。但是如果 还有microtast等其它的任务,就不止300ms了。

扩展一:

在面试过程中有时也会遇到这类问题。在这之前我以为考的是let和var的区别,其实它里面也包含着今天讲的知识。

for(var i =0 ;i < 3; i++) {
  console.log("for中i的值:"+i)
  var time = setTimeout(() => {
    console.log("setTimeout中i的值:"+i)
  }, 300);
}
复制代码

打印的结果导致是什么样的呢:

  • 1、当执行for循环的时候,定义了3个定时器,由于setTimeout是异步任务,所有这三个定时器,都会在300ms之后加入任务队列
  • 2、此时执行代码,依次输出个 for中i的值:1、2、3
  • 300ms之后,每个setTimeout的加入到任务队列,这时for循环早就执行完毕了,此时的 i 由于主线程执行完之后变成了3。由于这时setTimeout匿名回调函数保持对外部变量 i 的引用,所以最终再打印出3个 setTimeout中i的值:3

用let改变一下结果就不一样。最终依次打印出 setTimeout中i的值:0、1、2

for(let i =0 ;i < 3; i++) {
  console.log("for中i的值:"+i)
  var time = setTimeout(() => {
    console.log("setTimeout中i的值:"+i)
  }, 300);
}
复制代码
  • 1、var声明的变量,在全局范围内都有效,所以在全局只有一个变量i,每一次循环,变量i的值都会发生改变,而循环内部,被赋给setTimeout函数内部的i指向全局的i,结合之前讲的事件执行机制,最后一轮打印的i也都是3了
  • 2、let声明的变量,let只在块及作用域中有效,并且不存在变量提升。所以每次循环在setTimeout中的i都是一个新的变量。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通俗易懂的Vue异步更新策略及 nextTick 原理 的相关文章

随机推荐

  • Esper

    Esper Esper 的网址是 http esper codehaus org 我们可以访问该网站首页 有几种典型的应用最需要 Esper 我摘录如下 Business process management and automation
  • ORA-22835 缓冲区对于 CLOB 到 CHAR 转换或 BLOB 到 RAW 转换而言太小

    昨天遇到一个问题 ORA 22835 缓冲区对于 CLOB 到 CHAR 转换或 BLOB 到 RAW 转换而言太小 去找问题时候 发现是sql查询语句的to char方法将clob类型转换成varchar类型出了问题 oracle中var
  • Unity中贴图的导入

    Preferences中的Compress Assets on Import是决定资源导入时是否压缩资源 对于贴图资源来说 就是决定导入时是否压缩贴图 而TextureImporter中的贴图格式决定的是贴图的压缩格式 一个是导入 重新导入
  • 青龙2.10.13 稳定版+对接傻妞教程+短信登录+傻妞WEB控制台 超级详细

    此文章引用大佬的教程 进行更详细的阐述 如有疑问请进交流群332461037 我用的系统是centos7 6 目录 一 重装系统 1 选择centos7 6系统 2 重置服务器密码 3 服务器开放端口 二 ssh工具远程连接服务器 1 下载
  • 固件库编程:关于core_cm3.c的错误

    固件库编程 关于core cm3 c的错误 然后编译发现如下错误和警告 CMSIS CM3 core cm3 c 445 error non ASM statement in naked function is not supported
  • 基础算法:高精度除法

    高精度除法 题目条件 除数一定不为0 include
  • Numpy 索引 排序

    numpy argmax 和 numpy argmin numpy argmax 和 numpy argmin 函数分别沿给定轴返回最大和最小元素的索引 实例 numpy sort numpy sort 函数返回输入数组的排序副本 函数格式
  • Spring学习(三)--声明式事务&常用注解

    1 前言 这篇文章用来整理spring中的事务管理机制 声明式事务和常用的注解 一般的事务管理分为两种 编程式事务和声明式事务 spring提供声明式事务的支持 这样在我们操作数据库时更加方便 2 声明式事务 声明式事务是在AOP的基础上实
  • Ubuntu16.04+GTX1060mq(驱动版本430.64)安装CUDA10.0

    Ubuntu16 04 GTX1060mq 驱动版本430 64 安装CUDA10 0 CUDA下载 cuda最新版本下载地址 可在该页面进入历史版本下载 https developer nvidia com cuda downloads
  • 环境+代理配置+模块化

    1 模块化知识补充 1 1 模块化的基础 1 引入目录 默认引入目录中的index js文件 vuex modules a js b js index js 引入a js 引入 b js import store from vuex 是vu
  • Flutter(一)之Flutter的的简单入门分析

    前言 Flutter诞生于2018年 谷歌出品 应该是属于最新的移动跨平台开发框架了 从React Native自身框架的一些问题导致的用户量降低后 有很多小伙伴便转战Flutter战场 Flutter作为最新的跨移动平台开发框架 自然是汲
  • 使用Python,matplotlib绘制Nomogram列线图

    使用Python matplotlib绘制Nomogram列线图 1 效果图 2 源码 参考 这篇博客将介绍如何使用Python matplotlib绘制列线图 写这篇博客源于博友的提问 期望使用matplotlib绘制列线图如下 翻官网文
  • 浏览器访问.m3u8文件

    浏览器播放m3u8文件
  • PostgreSQL - tablefunc

    文章目录 创建扩展 tablefunc函数 1 normal rand 产生一个正态分布随机值 高斯分布 的集合 2 crosstab 行转列 1 3 crosstab 行转列 2 4 connectby 官方文档地址 创建扩展 creat
  • 关于 android 远程控制(pc 控制手机)

    因为手机的触屏有问题 需要通过pc来控制手机 试用 vnc viewer 没有成功 而且它是基于 wifi 的 然后不放弃 继续查找 终于发现 androidscreencast Desktop app to control an andr
  • Electron将Web页面打包成桌面应用实例

    上一篇文章 Electron vue脚手架改造vue项目 介绍了如何将Vue项目构建成桌面应用的方法 这篇文章将继续介绍Electron构建桌面项目 不仅仅局限于Vue项目 使用Vue项目做案例 只是目前做的Vue项目比较多 拿其中一个练手
  • 修改MySQL/MariaDB数据库root用户名和密码

    MySQL 5 7以下版本 更改密码 mysql u root p Enter password mysql gt use mysql 选择数据库 Database changed mysql gt update user set pass
  • Execl “此单元格中的数字为文本格式,或者其前面有撇号” 设成数字格式

    如何一次性批量将数字前面加上 撇 Excel批量设置数字转化成 以文本形式存储的数字 Excel批量为数值列加绿色小三角 正解 1 在数值前加个单撇号 2 选中列 进行分列操作 具体操作如下 选中该列 点击 菜单栏 中的 数据 分列 下一步
  • 谈谈修改寄存器默认值的几种方法和实现

    一 DFF的类型介绍 寄存器默认值 也叫复位值 是当reset或者set有效时寄存器输出的值 对于一个DFF来说 如下图 当reset为0时 Q输出0 当set为0时 Q输出为1 外部使用时保证reset与set不同时为0 图一 也就是说
  • 通俗易懂的Vue异步更新策略及 nextTick 原理

    最近在学习一些底层方面的知识 所以想做个系列尝试去聊聊这些比较复杂又很重要的知识点 学习就好比是座大山 只有自己去登山 才能看到不一样的风景 体会更加深刻 今天我们就来聊聊Vue中比较重要的异步更新策略及 nextTick 原理 在聊话题之