Vue 2 nextTick方法|异步更新|事件循环

1 nextTick的用处

vm.$netTick的作用是将回调延迟到下次DOM更新周期之后执行

它接受一个回调函数作为参数。

其实,在我们更新数据状态后,是不会立马渲染的,你不能即刻获取到新的DOM

<!DOCTYPE html>
<html><head><title>Async Update Example</title><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head><body><div id="app"><div ref="textBox">{{text}}</div><button @click="changeText">改变文本</button></div><script>new Vue({el: '#app',data:{text:"Today is a cloudy day."},methods:{changeText(){this.text=this.text=== "Today is a sunny day."?"Today is a cloudy day.": "Today is a sunny day.";console.log(this.$refs.textBox.innerHTML)}}});</script>
</body></html>

动画

此时,我们可以使用nextTick方法:

changeText(){this.text=this.text=== "Today is a sunny day."?"Today is a cloudy day.": "Today is a sunny day.";this.$nextTick(function(){this.$refs.textBox2.innerHTML = this.$refs.textBox1.innerHTML;});
}

动画

如果没有提供回调且在支持 Promise 的环境中,则返回一个 Promise。

changeText(){this.text=this.text=== "Today is a sunny day."?"Today is a cloudy day.": "Today is a sunny day.";_this=this;this.$nextTick().then(function(){_this.$refs.textBox2.innerHTML = _this.$refs.textBox1.innerHTML;});
}

测试中我们发现上面代码中then的回调参数里的this指向了window,所以我们在外面使用_this

2 异步更新机制

Vue侦测到数据变化时会通知到对应依赖管理器里的所有Watcher,然后虚拟DOM会对整个组件进行差异比较来更新DOM,Vue进行重新渲染。

如果我在一个循环中不停改变一个数据属性,那对应的Watcher就会收到多份通知,是不是要进行多次渲染呢?

明显不会,Vue.js会将收到的watcher实例添加到异步更新队列中,且不会重复添加同一个watcher,然后等到下一次事件循环,一次性清空队列里的所有watcher并让它们触发渲染

3 事件循环

3.1 什么是事件循环

前面提到的事件循环又是什么?

我们知道,JavaScript是一门单线程且非阻塞的语言。

单线程意味着一次只能执行一个任务,也叫做主线程。

非阻塞意味着遇到异步任务(比如网络请求、文件读取、定时器等)时,JavaScript会将这些异步任务挂起,继续执行后面的代码。当异步任务处理完毕后,根据一定的规则(通常是回调函数或Promise)来处理操作的结果。

挂起(pending)是指将异步任务放入一个队列里,称为事件队列

而异步任务可以分为微任务宏任务

微任务放在微任务队列,宏任务放在宏任务队列。

当主线程执行栈的任务都执行完后,检查微任务队列,执行微任务的回调事件,直到微任务队列为空,再检查宏任务队列,从中选出一个事件,将其回调加入执行栈,重复上述步骤

这也就是事件循环

3.1 常见微任务

1)Promise的then、catch和finally

当一个Promise的状态从pending变为fulfilled或reject时,与之相关的then或catch回调就会被添加到微任务队列。

console.log("开始");// 创建一个Promise对象
const myPromise = new Promise((resolve, reject) => {console.log("Promise中的同步代码");resolve("Promise成功"); // 模拟成功情况
});// 添加then、catch和finally回调
myPromise.then((result) => {console.log("then回调执行:", result);}).catch((error) => {console.error("catch回调执行:", error);}).finally(() => {console.log("finally回调执行");});console.log("Promise后的同步代码");// 模拟宏任务
setTimeout(() => {console.log("宏任务回调执行");
}, 0);console.log("结束");

输出

开始
Promise中的同步代码
Promise后的同步代码
结束
then回调执行: Promise成功
finally回调执行
宏任务回调执行

2)async/await

await后面的表达式会生成一个微任务。

console.log("开始");// 模拟一个异步函数,返回一个Promise
async function fetchData() {console.log("异步函数内部的同步代码");return "Promise成功"; // 模拟成功情况
}// 使用async/await来处理异步操作
async function processData() {try {const result = await fetchData(); // 等待Promise解决console.log("成功:", result);} catch (error) {console.error("失败:", error);} finally {console.log("finally回调执行");}
}// 调用async函数
processData();console.log("异步函数后的同步代码");// 模拟宏任务
setTimeout(() => {console.log("宏任务回调执行");
}, 0);console.log("结束");

输出

开始
异步函数内部的同步代码
异步函数后的同步代码
结束
成功: Promise成功
finally回调执行
宏任务回调执行

3)MutationObserver回调

MutationObserver是一个监视DOM树变化的API。

<!DOCTYPE html>
<html><head><title>MutationObserver示例</title><style>.text{color: red;}</style>
</head><body><div id="target"><p>这是一个段落。</p></div><script>// 选择要监视的目标元素const target = document.getElementById('target');// 创建一个MutationObserver实例,传入回调函数const observer = new MutationObserver(function (mutationsList, observer) {// 遍历变化列表中的每个MutationRecordfor (let mutation of mutationsList) {if (mutation.type === 'childList') {// 子节点变化console.log('子节点变化:', mutation.addedNodes, mutation.removedNodes);} else if (mutation.type === 'attributes') {// 属性变化console.log('属性变化:', mutation.target.className, mutation.oldValue);}}});// 配置MutationObserver选项,监视子节点变化const config = { childList: true, attributes: true, subtree: true, characterData: true };// 开始观察目标元素observer.observe(target, config);// 在一段时间后,修改目标元素,观察变化setTimeout(function () {target.innerHTML = '<p>这是一个新的段落。</p>';}, 1000);// 属性变化setTimeout(function () {target.classList.add('text')}, 2000);</script>
</body></html>

4)process.nextTick

node.js中进程相关的对象

console.log('这是第一个任务');
process.nextTick(function() {console.log('这是下一个微任务');
});
console.log('这是第二个任务');

5)queueMicrotask

这是一个ECMAScript 2020引入的方法。

queueMicrotask(function() {// 这是一个微任务
});

3.2 常见宏任务

1)定时器任务,如setTimeoutsetInterval

2)网络请求。

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/api/data', true);
xhr.onreadystatechange = function() {if (xhr.readyState === 4 && xhr.status === 200) {console.log('网络请求完成');}
};
xhr.send();

3)DOM操作,对DOM元素进行操作,例如添加、删除、修改元素。

DOM操作可能会导致页面的重新渲染和重排(reflow),这些操作是昂贵的,需要消耗较多的计算资源,因此它们通常被视为宏任务,而不是微任务。

你可以考虑使用 requestAnimationFrame 或其他微任务机制来优化DOM操作的性能。

4)文件操作

const fs = require('fs');
fs.readFile('example.txt', 'utf8', function(err, data) {if (err) throw err;console.log('读取文件完成');
});

4 nextTick源码

import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'//指示是否正在使用微任务来处理异步操作
export let isUsingMicroTask = false//存储待执行的回调函数
const callbacks: Array<Function> = []
//是否有待执行的回调
let pending = false//用于执行回调函数。它将 callbacks 数组中的回调函数依次执行,并在执行后清空 callbacks 数组
function flushCallbacks() {pending = falseconst copies = callbacks.slice(0)callbacks.length = 0for (let i = 0; i < copies.length; i++) {copies[i]()}
}//根据环境选择使用微任务或宏任务来执行回调函数
let timerFunc//如果浏览器支持原生的 Promise,则使用 Promise 来实现微任务。
if (typeof Promise !== 'undefined' && isNative(Promise)) {const p = Promise.resolve()timerFunc = () => {p.then(flushCallbacks)//在 iOS 上使用 UIWebView 时,添加一个空的 setTimeout(noop) 来强制刷新微任务队列if (isIOS) setTimeout(noop)}isUsingMicroTask = true
} else if (!isIE &&typeof MutationObserver !== 'undefined' &&(isNative(MutationObserver) ||MutationObserver.toString() === '[object MutationObserverConstructor]')
) {//如果浏览器不支持原生 Promise,但支持 MutationObserver,则使用 MutationObserver 来实现微任务let counter = 1const observer = new MutationObserver(flushCallbacks)const textNode = document.createTextNode(String(counter))observer.observe(textNode, {characterData: true})//这种情况下,timerFunc 将观察一个文本节点的字符数据变化来触发回调函数的执行timerFunc = () => {counter = (counter + 1) % 2textNode.data = String(counter)}isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {timerFunc = () => {setImmediate(flushCallbacks)}
} else {timerFunc = () => {setTimeout(flushCallbacks, 0)}
}

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

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

相关文章

[论文笔记]ESIM

引言 这是经典论文Enhanced LSTM for Natural Language Inference的笔记。 本篇论文文是建立在自然语言推理(Natural Language Inference,NLI)任务上的。提出了简单的通过基于LSTM的序列推理模型效果到达了当时的SOTA水平。同时基于该模型,在局部推理建模层和推理组合层使用了…

嵌入式岗位笔试面试专栏 - 岗位介绍

文章目录 一、嵌入式岗位的分类二、热门领域及公司三、发展前景四、技能要求沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们将讲解嵌入岗位的工作职责 。 一、嵌入式岗位的分类 嵌入式软件工程师大致可以分为两种类型: 应用开发工程师驱动开发工程师应用工程…

安全基础 --- 原型链污染

原型链 大部分面向对象的编程语言&#xff0c;都是通过“类”&#xff08;class&#xff09;实现对象的继承。传统上&#xff0c;JavaScript 语言的继承不通过 class&#xff0c;而是通过“原型对象”&#xff08;prototype&#xff09;实现 1、prototype 属性的作用 JavaScri…

蝶形运算法

蝶形运算法是一种基于FFT&#xff08;Fast Fourier Transform&#xff09;算法的计算方法&#xff0c;其基本思想是将长度为N的DFT分解成若干个长度为N/2的DFT计算&#xff0c;并通过不断的合并操作得到最终的结果。该算法也称为“蝴蝶算法”&#xff0c;因为它的计算过程中需要…

Git 版本回退 超神步骤

Git 版本回退 一. 背景 多版本分支开发&#xff0c;合并版本问题太多&#xff0c;需要回滚到某次版本。我的git客服端工具是 sourcetree 二.操作步骤 2.1 切到当前需要回退版本的分支 2.2 右击需要具体某一个分支&#xff0c;这个分支就是你想切到的分支版本&#xff0c;具体…

Spark 环境安装与案例演示

Spark 环境安装 一、准备工作 1、hadoop成功安装 2、防火墙关闭 二、解压安装 1、上传 spark 安装包到/tools 目录&#xff0c;进入 tools 下&#xff0c;执行如下命令&#xff1a; tar -zxvf spark-2.1.0-bin-hadoop2.7.tgz -C /training/由于 Spark 的脚本命令和 Hadoop…

12 最小覆盖串

最小覆盖串 题解1 滑窗双指针模板&#xff08;labuladong&#xff0c;高效好套&#xff0c;length版&#xff09; 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 "&quo…

wpf从cs代码创建简单3D物体和3D Tools研究

前面已经说了&#xff0c;WPF项目中引入3DTools dll之后&#xff0c;在xaml中加入它的命名空间&#xff0c; xmlns:tools"clr-namespace:_3DTools;assembly3DTools" 把<Viewport3D>标签包含在<tools:TrackballDecorator>标签之中&#xff0c;就可以用鼠…

ping: www.baidu.com: Name or service not known 写了DNS还是不行

环境描述&#xff1a;ESXI平台上&#xff0c;一台Centos7虚拟主机。 问题描述&#xff1a;平台上的其他的虚拟机可以正常ping通&#xff0c;就这台ping IP地址可以通&#xff0c;ping域名解析失败。 排查过程&#xff1a; 1、检查网卡配置文件和/etc/resolv.conf配置文件是否…

【SQL学习笔记】关系模型与查询和更新数据

一、关系模型 1.1 主键 主键是关系表中记录的唯一标识。主键的选取非常重要&#xff1a;主键不要带有业务含义&#xff0c;而应该使用BIGINT自增或者GUID类型。主键也不应该允许NULL。 可以使用多个列作为联合主键&#xff0c;但联合主键并不常用。 1.2 外键 FOREIGN KEY …

0010Java程序设计-springboot+vue影院售票系统设计与实现

摘 要目 录系统实现开发环境 摘 要 看电影已经成为了人们生活中不可缺少的一部分&#xff0c;电影院售票及管理系统是电影院的日常管理及售票任务的核心&#xff0c; 在电影院中&#xff0c; 工作人员并非只是放映电影&#xff0c; 还有诸如票房统计、影片放映、影片场次安排、…

PE文件格式详解

摘要 本文描述了Windows系统的PE文件格式。 PE文件格式简介 PE&#xff08;Portable Executable&#xff09;文件格式是一种Windows操作系统下的可执行文件格式。PE文件格式是由Microsoft基于COFF&#xff08;Common Object File Format&#xff09;格式所定义的&#xff0c…

淘宝数据库,主键如何设计的?

聊一个实际问题&#xff1a;淘宝的数据库&#xff0c;主键是如何设计的&#xff1f; 某些错的离谱的答案还在网上年复一年的流传着&#xff0c;甚至还成为了所谓的 MySQL 军规。其中&#xff0c;一个最明显的错误就是关于MySQL 的主键设计。 大部分人的回答如此自信&#xff…

论文阅读_大模型_ToolLLM

英文名称: ToolLLM: Facilitating Large Language Models to Master 16000 Real-world APIs 中文名称: TOOLLLM&#xff1a;帮助大语言模型掌握16000多个真实世界的API 文章: http://arxiv.org/abs/2307.16789 代码: https://github.com/OpenBMB/ToolBench 作者: Yujia Qin 日期…

保姆级 C++ 学习路线

上周有小伙伴留言求安排一手C/C学习路线&#xff0c;这周一份保姆级的C语言安排上&#xff01; 以前就写过C语言的学习路线&#xff1a;可能是北半球最好的零基础C语言学习路线&#xff0c;这次把C的学习路线也安排上&#xff0c;专门花了一个多月写了这篇学习路线&#xff0c;…

[Linux]编写一个极简版的shell(版本1)

[Linux]编写一个极简版的shell-version1 文章目录 [Linux]编写一个极简版的shell-version1命令行提示符打印接收命令行参数将命令行参数进行解释执行用户命令完整代码 本文能够帮助Linux系统学习者通过代码的角度更好地理解命令行解释器的实现原理。 命令行提示符打印 Linux操…

常用命令之mysql命令之show命令

一、mysql show命令简介 mysql数据库中show命令是一个非常实用的命令&#xff0c;SHOW命令用于显示MySQL数据库中的信息。它可以用于显示数据库、表、列、索引和用户等各种对象的信息。我们常用的有show databases&#xff0c;show tables&#xff0c;show full processlist等&…

SpringMVC常用注解、参数传递及页面跳转

一.SpringMVC常用注解 1.1.RequestMapping RequestMapping注解是一个用来处理请求地址映射的注解&#xff0c;可用于映射一个请求或一个方法&#xff0c;可以用在类或方法上。 标注在方法上运行代码 用于方法上&#xff0c;表示在类的父路径下追加方法上注解中的地址将会访…

无涯教程-JavaScript - NORMDIST函数

NORMDIST函数替代Excel 2010中的NORM.DIST函数。 描述 该函数返回指定均值和标准差的正态分布。此功能在统计中有非常广泛的应用,包括假设检验。 语法 NORMDIST(x,mean,standard_dev,cumulative)争论 Argument描述Required/OptionalXThe value for which you want the dis…

Redis——认识Redis

简单介绍 Redis诞生于2009年&#xff0c;全称是Remote Dictionary Server&#xff0c;远程词典服务器&#xff0c;是一个基于内存的键值型NoSQL数据库。 特征 键值&#xff08;Key-value&#xff09;型&#xff0c;value支持多种不同数据结构&#xff0c;功能丰富单线程&…