Vue中$nextTick实现源码解析

news2024/9/22 13:32:11

这篇文章主要为大家介绍了Vue中$nextTick实现源码解析,有需要的朋友可以借鉴参考下!

先看一个简单的问题

{{ text }}

此时打印的结果是什么呢?是 'old'。如果想让它打印 'new',使用 nextTick 稍加改造就可以

this.$nextTick(() => {
  console.log(this.$refs.div.innerText)
})

内部实现

但是你想过它内部是怎么实现的么,和我们写 setTimeout 有什么区别呢?

因为平时工作使用的是Vue2,所以我就以Vue2的最新版本2.6.14为例进行分析,Vue3的实现应该也是大同小异。

源码地址:github.com/vuejs/vue/b…

为了方便阅读我删掉了注释,只关注最重要的实现

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]'
)) {
  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)) {
  timerFunc = () => {
setImmediate(flushCallbacks)
  }
} else {
  timerFunc = () => {
setTimeout(flushCallbacks, 0)
  }
}

先大概扫一遍可知 $nextTick 主要是通过微任务来实现的,其实在2.5版本中,是采用宏任务与微任务相结合的方式实现的,但因为在渲染和事件处理中一些比较怪异的行为(感兴趣的话可以看下issue),所以最终统一采用了微任务。

先看第一块:

if (typeof Promise !== 'undefined' && isNative(Promise)) {
  const p = Promise.resolve()
  timerFunc = () => {
p.then(flushCallbacks)
if (isIOS) setTimeout(noop)
  }
  isUsingMicroTask = true
}

如果可以使用 Promise ,就采用 promise.then 的方式去执行回调,将任务在下一个tick执行。但是其中 if (isIOS) setTimeout(noop) 这句话是在做什么呢?在iOS >= 9.3.3的UIWebView中,定义的回调函数通过 Promise 的方式推到微任务队列后,队列不刷新,需要靠 setTimeout 来强制更新一下,noop 就是一个空函数。

再看第二块:

else if (!isIE && typeof MutationObserver !== 'undefined' && (
  isNative(MutationObserver) || MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
  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
}

如果不能用 Promise 就降级使用 MutationObserver。创建了一个文本节点,并通过 observer 去观察文本节点的变化。 characterData: true 这个配置就是当文字变化的时候就会执行回调。(counter + 1) % 2 会使文本节点的文字在 0 、 1 、 0 、 1之间不同变化,这样就会被 observer 观察到。MutationObserver 也是微任务。

然后是第三块:

else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { 
  timerFunc = () => { 
setImmediate(flushCallbacks) 
  } 
}

当微任务都不被支持时,就要使用宏任务了。其实大多数情况下都不会走到这里,因为 setImmediate 并没有成为正式的标准,并且兼容性很差。

最后是第四块:

else {
  timerFunc = () => {
setTimeout(flushCallbacks, 0)
  }
}

最后在所有方案都行不通时,只能采用 setTimeout 的方式。之所以有第三块是因为虽然都是宏任务,但是 setImmediate 会比 setTimeout 快,所以MDN上才会说 setTimeout(fn, 0) 不能成为 setImmediate 的polyfill。就像作者在注释中写的那样:它仍然是比 setTimeout 更好的选择。

一步一步分析了 $nextTick 源码后,你是否对它的用法理解更加透彻了呢?

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

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

相关文章

【计组笔记】06_指令系统

5.1 指令系统概述及指令格式 1. 指令的基本概念 2. 指令的分类 根据计算机层次结构分类 根据指令中地址码字段的个数分类 根据指令中操作数的物理位置分类 根据指令的功能分类 3. 指令格式 4. 指令的再认识 5. 指令格式举例 5.2 寻址方式及指令寻址 1. 寻址方式的概念 2.…

[论文阅读] 颜色迁移-Correlated Color Space

[论文阅读] 颜色迁移-Correlated Color Space 文章: Color transfer in correlated color space, [paper], [matlab code], [opencv code] 1-算法原理 本文算法比较简单, 其原理是把原始图像本身的空间分布进行归一化, 然后通过旋转平移缩放等变换, 变换到目标图像的空间分布…

WMS手动配货和自动配货的区别

手动配货 不知道配货流程的朋友可以看一下前面的文章链接: 深入浅出WMS之出库流程里面有对出库的解释说明,其中也有对配货的解释。前端页面也可以在前面的那篇文章中看到,这里我们来说一下后端部分。 查 手动配货是选中出库单的某条数据,然…

一文教你从Linux内核角度探秘JDK NIO文件读写本质(上)

1. 前言 在深入讲解Netty那些事儿之从内核角度看IO模型一文中曾对 Socket 文件在内核中的相关数据结构为大家做了详尽的阐述。 Socket内核结构.png 又在此基础之上介绍了针对 socket 文件的相关操作及其对应在内核中的处理流程: 系统IO调用结构.png 并与 epoll 的…

由阿里三位专家撰写:数据库高效优化:架构、规范SQL技巧文档

引言 学习是一种基础性的能力。然而,“吾生也有涯,而知也无涯。”,如果学习不注意方法,则会“以有涯随无涯,殆矣”。 学习就像吃饭睡觉一样,是人的一种本能,人人都有学习的能力。我们在刚出生…

[附源码]计算机毕业设计springboot作业管理系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

词袋模型(Bag-of-words model)

词袋模型词袋模型简介示例计算机视觉中的词袋模型词袋模型 简介 词袋模型(Bag-of-words model)是用于自然语言处理和信息检索中的一种简单的文档表示方法。通过这一模型,一篇文档可以通过统计所有单词的数目来表示,这种方法不考…

redis安装

版本号:redis-6.2.1 下载redis-6.2.1.tar.gz放/opt目录 解压命令:tar -zxvf redis-6.2.1.tar.gz 解压完成后进入目录:cd redis-6.2.1 在redis-6.2.1目录下执行make命令 出现make test 执行make install 查看redis默认安装路径:/u…

二、CANdelaStudio入门-版本介绍

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio的各个版本,欢迎各位朋友订阅、评论,可以…

PbootCMS简单两步增加自动清理日志功能

问:网站没人访问触发不了清理怎么办? 答:我建议你不要关心这个,都没人访问你的网站,你还有个锤子东西需要清理? 问:听人说前台插入script触发会不安全? 答:都是成年人…

Web应用程序,简单的日志系统解决方案

一、简介 今天介绍一下,当你的程序没有日志系统时,如何快速方便查看当前程序日志的解决方案。如果你的程序有日志系统,可以不看本篇博客哈。本文实例是使用 C# 讲解,当然实现的核心思想适用于其他语言开发的系统。 二、解决方案…

nexus搭建测试dockermavennpm仓库

JAVA下载 https://www.oracle.com/java/technologies/downloads/archive/ https://login.oracle.com/mysso/signon.jsp QQq951699. [rootvm1 ~]# mkdir -p /data [rootvm1 ~]# mv jdk-8u221-linux-i586.tar.gz /data [rootvm1 ~]# cd /data;tar xf jdk-8u221-linux-i586.tar.g…

222页8万字智慧园区IOC平台运维管理平台解决方案

目 录 第一章 项目概述 7 1.1 园区格局的变化 7 1.1.1 传统安防面临的不足与挑战 7 1.1.2 园区安防未来的发展趋势 7 1.2 需求分析 8 1.2.1 平台集成化 8 1.2.2 数据可视化 8 1.2.3 管控全面化 8 1.2.4 覆盖高清化 9 1.2.5 指挥简易化 9 1.2.6 建设智能化 9 1.3 建设思路 9 1.3…

基于物联网设计的自反馈深紫外杀菌消毒系统(STM32F407)

一、前言 目前常态化防控病毒有很多种,其中主要是人工喷洒消毒液这种消毒方式,这种消毒效果无法得到量化,同时还可能存在喷洒盲区,也会对公民的呼吸道产生刺激,腐蚀损坏公共设施,而对于室内公共空间的消毒的要求会更高,基于这样的状况,人工喷洒消毒液这种方式肯定不太…

[附源码]JAVA毕业设计教学成果管理平台(系统+LW)

[附源码]JAVA毕业设计教学成果管理平台(系统LW) 目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术…

C语言——利用矩阵LU分解法求逆、行列式

本章介绍了LU分解法,以及如何利用LU分解法求逆、行列式,针对每个公式、原理、代码进行了详细介绍,希望可以给大家带来帮助。 目录 LU分解法 概念 确定L、U矩阵 LU分解法的意义 程序设计 LUP求逆 1)代码 2)代…

uniapp 监听通知栏消息插件(支持白名单、黑名单、过滤) Ba-NotifyListener

简介(下载地址) Ba-NotifyListener 是一款实时监听通知栏消息的uniapp插件。支持白名单、黑名单;支持监听消息移除;支持自定义过滤条件(如短信验证码)等。 支持监听所有通知栏消息(包含id、ti…

springboot整合layui排坑

参考:thymeleaflayui加载页面渲染时TemplateProcessingException: Could not parse as expression: "_yaoshengting的博客-CSDN博客 目录 1.table渲染问题 2.解决方式 1.将clos后的[[ ]]分成四行写 2.加上 th:inline"none 1.table渲染问题 源代码&…

[附源码]Python计算机毕业设计Django拉勾教育课程管理系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

spark shuffle·读写流程 和 rdd持久化

1.对比mapreduce和spark mapreduce里 map的第3条就是说,比如我存了很多条数据,如果一条一条写进磁盘,肯定有很多次IO,我先归并到一个缓存里面再溢写磁盘。 spark与其的差别就是用map代替了buffer,因为map存的key唯一&…