$nextTick底层原理(详细) - vue篇

公众号:需要以下pdf,关注下方


2023已经过完了,让我们来把今年的面试题统计号,来备战明年的金三银四!所以,不管你是社招还是校招,下面这份前端面试工程师高频面试题,请收好。

前言

nextTick 是 Vue 的一个核心实现,$nextTick方法将回调延迟到下次DOM更新循环之后执行。Vue 的 nextTick 其本质是对 JavaScript 执行原理 EventLoop 的一种应用。

nextTick 的核心是利用了如 Promise 、MutationObserver、setImmediate、setTimeout的原生 JavaScript 方法来模拟对应的微/宏任务的实现,本质是为了利用 JavaScript 的这些异步回调任务队列来实现 Vue 框架中自己的异步回调队列

前置知识 - js事件循环

JS 运行机制

JS 执行是单线程的,基于事件循环。事件循环大致分为以下步骤:

  1. 所有同步任务都在主线程上执行,形成一个执行栈。
  2. 异步任务放进任务队列,异步任务分为宏任务和微任务
  3. 执行栈所有同步任务执行完成,就会执行任务队列。对应的异步任务,结束等待状态,进入执行栈,开始执行。
  4. 主线程不断重复上面的第三步。

主线程的执行过程就是一个 tick,而所有的异步结果都是通过 “任务队列” 来调度。 消息队列中存放的是一个个的任务(task)。 task 分为两大类,分别是 macro task 和 micro task,并且每个 macro task(宏任务) 结束后,都要清空所有的 micro task(微任务)。

如图所示

 
for (macroTask of macroTaskQueue) {
    // 执行宏任务
    handleMacroTask();
      
    // 执行所有微任务
    for (microTask of microTaskQueue) {
        handleMicroTask(microTask);
    }
}

宏任务: script、setTimeout、setInterval、Node中的setImmediate 等
微任务: Promise.then、MutationObserver、Node 中的 Process.nextTick等

nextTick的具体实现原理

上源码

源码分为两部分,一是判断当前环境能使用的 API 并保存异步函数,二是调用异步函数执行回调队列

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

 
Promise.then`、`MutationObserver`、`setImmediate`、`setTimeout

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

 
export let isUsingMicroTask = false 
const callbacks = [] // 回调队列
let pending = false

// 该方法执行队列中的全部回调
function flushCallbacks () {
  pending = false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  // 执行任务队列
  for (let i = 0; i < copies.length; i++) {
    copies[i]()
  }
}
let timerFunc // 用来保存调用异步任务方法
// 判断1:是否原生支持Promise
if (typeof Promise !== 'undefined' && isNative(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:是否原生支持setImmediat
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  //判断4:上面都不行,直接用setTimeout
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}

 
export function nextTick(cb?: Function, ctx?: Object) {
  let _resolve;
​
  // cb 回调函数会经统一处理压入 callbacks 数组
  callbacks.push(() => {
    if (cb) {
      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;
    });
  }
}

callbacks就是异步操作队列

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

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

把回调函数放入callbacks等待执行,将执行函数放到微任务或者宏任务中 无论是微任务还是宏任务,都会放到flushCallbacks使用,这里将callbacks里面的函数复制一份,同时callbacks置空

循环遍历执行callbacks里面的函数

总结

  1. Vue 的 nextTick 其本质是对 JavaScript 执行原理 EventLoop 的一种应用
  2. nextTick核心是利用了如 Promise 、MutationObserver、setImmediate、setTimeout的原生 JavaScript 方法来模拟对应的微/宏任务的实现,根据当前环境支持什么方法则确定调用哪个


原文链接:https://juejin.cn/post/7314493016497684520
 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CUDA学习笔记04:向量之和

参考资料 CUDA编程模型系列二(向量操作)_哔哩哔哩_bilibili &#xff08;非常好的学习资料&#xff01;&#xff09; vs2019 随意新建一个空项目&#xff0c;按照之前的环境配置配好项目依赖&#xff1a; CUDA学习笔记02&#xff1a;测试程序hello world-CSDN博客 代码结构…

jitpack上传aar异常: ERROR: No build artifacts found

问题 如图所示&#xff0c;提示 ERROR: No build artifacts found 解决 无法找到artifacts的情况下&#xff0c;我们就需要手动添加artifacts 。 //maven-publish 插件的配置 // publishing 用于定义项目的发布相关配置 publishing {// 配置maven 仓库repositories { Repo…

5201B数据网络测试仪

|5201B数据网络测试仪| | 产品综述 | 电科思仪5201B便携式数据网络测试仪&#xff0c;集成高性能IP基础测试硬件平台&#xff0c;提供L2-L3流量测试及协议仿真解决方案&#xff0c;支持以太网报文线速生成与分析、统计、报文捕获&#xff0c;以及路由、接入、组播、数据中心等协…

item_fee-获得淘宝商品快递费用 API调用说明获取测试key

item_fee-获得淘宝商品快递费用 .通过传入商品id、区域id&#xff0c;来获取该商品的快递费用。 公共参数 点此获取API请求地址 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&a…

Linux系统的服务/进程

系统守护进程&#xff08;服务&#xff09; •服务就是运行在网络服务器上监听用户请求的进程 •服务是通过端口号来区分的 常见的服务及其对应的端口 1.ftp&#xff1a;21 FTP指的是文件传输协议&#xff0c;它是用于在计算机网络上进行文件传输的标准网络协议。通过FTP&am…

数字化转型导师坚鹏:成为数字化转型顾问 引领数字化美好未来

成为数字化转型顾问 引领数字化美好未来 ——数字化人才与企业的共赢之路 数字经济新时代&#xff0c;中国企业向数字化转型要效益&#xff1b; 转型顾问创未来&#xff0c;职场精英借数字化转型成良师。 我们中国政府特别重视数字经济发展及数字化人才培养。早在2020年8月2…

通过XML调用CAPL脚本进行测试(新手向)

目录 0 引言 1 XML简介 2 通过XML调用CAPL脚本 0 引言 纪念一下今天这个特殊日子&#xff0c;四年出现一次的29号。 在CANoe中做自动化测试常用的编程方法有CAPL和XML两种&#xff0c;二者各有各的特色&#xff0c;对于CAPL来说新手肯定是更熟悉一些&#xff0c;因为说到在C…

C#高级:Winform桌面开发中DataGridView的详解

一、每条数据增加一个按钮&#xff0c;点击输出对应实体 请先确保正确添加实体的名称和文本&#xff1a; private void button6_Click(object sender, EventArgs e) {//SQL查询到数据&#xff0c;存于list中List<InforMessage> list bll.QueryInforMessage();//含有字段…

动静态库-动态库加载

动静态库 前言引入 一、静态库1. 创建静态库①原理②创建 2. 使用静态库①借助编译选项②只需要带库名 3. 小结 二、动态库1. 创建动态库2. 使用动态库 三、 动态库加载原理——进程地址空间1. 地址①程序没有被加载前的地址②程序加载后的地址 2. 原理①动态库的地址②原理 前…

Redis中的单线程高性能原因和其他高级命令

单线程 Redis是单线程吗&#xff1f; Redis的单线程主要是指Redis的网络IO和键值对读写是由一个线程来完成的&#xff0c;这也是 Redis对外提供键值存储的主要流程。但Redis的其他功能&#xff0c;比如持久化、异步删除、 集群数据同步等&#xff0c;其实是由额外的线程执行的…

Spring Cloud 面试题及答案整理,最新面试题

Spring Cloud中断路器的原理及其作用是什么&#xff1f; Spring Cloud断路器的原理和作用基于以下几个关键点&#xff1a; 1、故障隔离机制&#xff1a; 在微服务架构中&#xff0c;断路器作为一种故障隔离机制&#xff0c;当某个服务实例出现问题时&#xff0c;断路器会“断…

紫光展锐携手中兴通讯成功完成业界首个5G N102芯网一体方案联调

近日&#xff0c;紫光展锐携手中兴通讯成功完成业界首个5G N102频段的芯网一体方案联调&#xff0c;包括5G NR数据呼叫、时延和峰值速率测试等用例。这是双方在5G产品和研发方面取得的重大创新成果&#xff0c;为推动N102频段在5G行业的应用奠定了坚实基础。 3GPP定义的N102频段…

软件测试 - 测试用例基本理论

1. 概念 为了特定的目的(该目的是检验代码是否满足用户需求)而设计的文档&#xff0c;文档包含测试输入、执行条件、预期结果等。文档的形式一般是excel表格。 比如说我们买了一台电脑&#xff0c;新买的笔记本检查完外观之后第一步需要查看电脑是否能够正常开机&#xff0c;…

用Python爬取古诗文网的各类古诗

fetch-gushiwen 用途 可以拿去用于个人知识库、知识图谱的创建等其他学习用途。 使用 输入古诗文网的链接&#xff0c;即可爬取该页面所有诗歌的诗名&#xff0c;作者&#xff0c;朝代&#xff0c;内容&#xff0c;译文&#xff0c;注释&#xff0c;赏析&#xff0c;创作背…

MySQL 缓存策略

MySQL 缓存方案用来干什么 ? 缓存用户定义的热点数据&#xff0c;用户直接从缓存中获取热点数据&#xff0c;降低数据的读写压力。场景分析 内存访问速度是磁盘访问速度的 10 万倍。读的需求远远大于写的需求MySQL 自身缓冲层跟业务无关。MySQL 作为项目主要数据库&#xff0…

P5076 【深基16.例7】普通二叉树(简化版)题解

题目 您需要写一种数据结构&#xff0c;来维护一些数&#xff08;都是绝对值以内的数&#xff09;的集合&#xff0c;最开始时集合是空的。其中需要提供以下操作&#xff0c;操作次数q不超过&#xff1a; 定义数x的排名为集合中小于x的数的个数1。查询数x的排名。注意x不一定…

【ICM】好奇心机制

文章目录 样本经验处理降低图片像素和通道构建连续状态捕捉动作经验回放类 各部分的模型编码器模型反向模型正向模型DQN模型ICM 的 反向传播 概念补充强化学习组成元素按照学习目标来分按照策略更新方式区分强化学习on-line 与 off-line经验回放 全部代码 样本经验处理 降低图…

什么是物联网?物联网如何工作?

物联网到底是什么&#xff1f; 物联网(Internet of Things&#xff0c;IoT)的概念最早于1999年被提出&#xff0c;官方解释为“万物相连的互联网”&#xff0c;是在互联网基础上延伸和扩展&#xff0c;将各种信息传感设备与网络结合起来而形成的一个巨大网络&#xff0c;可以实…

无法启动报,To install it, you can run: npm install --save @/components/iFrame/index

运行的过程中后台报错 npm install --save /components/iFrame/index&#xff0c;以为是安装三方依赖错误&#xff0c;经过多次重装node_modules依然没有用。 没办法&#xff0c;只能在项目中搜索 components/iFrame/index这个文件。。突然醒悟。。。 有时候&#xff0c;犯迷…

MySQL面试题【全面】2024

基础内容 1、MySQL的架构分层 &#xff08;1&#xff09;Serve层&#xff1a;负责建立连接、分析和执行 SQL。 MySQL 大多数的核心功能模块都在这实现&#xff0c;主要包括连接器&#xff0c;查询缓存、解析器、预处理器、优化器、执行器等。另外&#xff0c;所有的内置函数&…