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.rhkb.cn/news/120391.html

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

相关文章

NPM 常用命令(三)

目录 1、npm compltion 1.1 描述 2、npm config 2.1 常用命令 2.2 描述 set get list delete edit fix 2.3 配置 json global editor location long 3、npm dedupe 3.1 描述 3.2 配置 4、npm deprecate 4.1 命令使用 4.2 描述 4.3 配置 registry ot…

CentOS7 Hadoop3.3.0 安装与配置

一、安装JDK 1、创建文件夹tools和training用于存放压缩包和解压使用&#xff0c;tools存放压缩包&#xff0c;training用于解压后安装jdk和hadoop的路径。 1&#xff09;回到路径为 / 的位置 cd /2) 创建 tools 和 training mkdir toolsmkdir training3) 进入tools文件夹 …

RHCA之路---EX280(4)

RHCA之路—EX280(4) 1. 题目 Use the S2I functionality of your OpenShift instance to build an application in the rome project Use the Git repository at http://services.lab.example.com/php-helloworld for the application source Use the Docker image labeled re…

Three.js开发中遇到的常见问题总结和性能优化

关于Three.js开发中遇到的一些问题总结 1.加载外部模型文件无法在场景中显示: (1) 确保当前文件内容是否能被读取&#xff0c;在Javascript的console中查找错误&#xff0c;并确定当你调用.load()的时候&#xff0c;使用了onError回调函数来输出结果, 如果err 输出则表示当前…

一加11/Ace2/10Pro手机如何实现全局120HZ高刷-游戏超级流畅效果

已经成功root啦。安卓13目前也一样支持LSPosed框架&#xff0c;如果你对LSP框架有需求&#xff0c;也可以使 自测120HZ刷新率诞生以后&#xff0c;很多小伙伴用上了就很难回来啦&#xff0c;一加11/Ace2/10Pro/9pro手 机厂商也对新机做了很多的适配&#xff0c;让我们日常使用起…

工业4G路由器的户外组网与无人值守场景应用

工业4G路由器是专为不便电缆布线的工业或日晒雨淋网络不畅的户外环境所设计的网络设备。它能够在没有光纤宽带的情况下使用插卡的方式提供4G或无线WiFi的网络支持。具备工业级防水功能&#xff0c;能够在户外环境下进行网络部署&#xff0c;并实现无人值守运行。工业4G路由器还…

SpringMVC使用

文章目录 一.MVC基础概念1.MVC定义2.SpringMVC和MVC的关系 二.SpringMVC的使用1.RequestMapping2.获取参数1.获取单个参数2.传递对象3.后端参数重命名&#xff08;后端参数映射&#xff09;4.获取URL中参数PathVariable5.上传文件RequestPart6.获取Cookie/Session/header 3.返回…

聚焦!智慧燃气使用体验到底怎么样?

文章来源&#xff1a;网络 关键词&#xff1a;智慧燃气、智能管网、智能气网、智慧燃气系统、智慧燃气平台 随着科技的发展&#xff0c;物联网技术不断进步&#xff0c;智能燃气也时常出现在我们的生活中。但大多数人仍然对智慧燃气知之甚少。究竟何为智慧燃气&#xff1f;能…

如何将Word转成PDF?试一下这个转换方法

Word转成PDF是现代办公中常见的需求&#xff0c;它可以确保文件的格式和内容在不同平台上保持一致&#xff0c;并且更加方便共享和打印。在这个数字化时代&#xff0c;我们经常需要将Word文档转换为PDF格式&#xff0c;无论是个人用户还是商务用户都会遇到这样的需求。那么如何…

IP地址、网关、网络/主机号、子网掩码关系

一、IP地址 IP地址组成 IP地址分为两个部分&#xff1a;网络号和主机号 &#xff08;1&#xff09;网络号:标识网段&#xff0c;保证相互连接的两个网段具有不同的标识。 &#xff08;2&#xff09;主机号:标识主机&#xff0c;同一网段内&#xff0c;主机之间具有相同的网…

介绍几个搜索引擎

Google&#xff1a;全球最大的搜索引擎&#xff0c;提供全面的搜索服务&#xff0c;包括网页、图片、视频、新闻、地图等。 Baidu&#xff1a;中国最大的搜索引擎&#xff0c;提供类似于Google的全面搜索服务&#xff0c;同时也有网盘、知道等功能。 Bing&#xff1a;微软公司…

一种编程语言,

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

初识Maven(一)命令行操作和idea创建maven工程

Maven 是 Apache 软件基金会组织维护的一款专门为 Java 项目提供**构建**和**依赖**管理支持的工具。 构建过程包含的主要的环节&#xff1a;- 清理&#xff1a;删除上一次构建的结果&#xff0c;为下一次构建做好准备 - 编译&#xff1a;Java 源程序编译成 *.class 字节码文件…

【AI】机器学习——绪论

文章目录 1.1 机器学习概念1.1.1 定义统计机器学习与数据挖掘区别机器学习前提 1.1.2 术语1.1.3 特点以数据为研究对象目标方法——基于数据构建模型SML三要素SML步骤 1.2 分类1.2.1 参数化/非参数化方法1.2.2 按算法分类1.2.3 按模型分类概率模型非概率模型逻辑斯蒂回归 1.2.4…

力扣刷题49 字母 异位词分组

目录 题目描述代码实现基本实现优化代码 基础知识回溯集合 参考 题目描述 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs [“eat”, “tea”…

桌面应用小程序,一种创新的跨端开发方案

Qt Group在提及2023年有桌面端应用程序开发热门趋势时&#xff0c;曾经提及三点&#xff1a; 关注用户体验&#xff1a;无论您是为桌面端、移动端&#xff0c;还是为两者一起开发应用程序&#xff0c;有一点是可以确定的&#xff1a;随着市场竞争日益激烈&#xff0c;对产品的期…

Vue框架--Vue中的属性监听

1.侦听属性概述 Vue提供了对属性变化的侦听操作,使用watch关键字实现。当被监视的属性变化时, 回调函数自动调用, 进行相关操作。这里需要注意的是你所侦听的属性必须存在。 2.代码实现 可以使用两种方式实现属性的侦听。 第一种:我们把侦听属性作为一个配置项目,放入Vue实…

ctfhub ssrf(3关)

文章目录 内网访问伪协议读取文件扫描端口 内网访问 根据该题目&#xff0c;是让我们访问127.0.0.1/falg.php&#xff0c;访问给出的链接后用bp抓包&#xff0c;修改URL&#xff0c;发送后得到flag&#xff1a; 伪协议读取文件 这题的让我们用伪协议&#xff0c;而网站的目录…

用WebGPU实现基于物理的渲染

推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 最近&#xff0c;我花了相当多的时间在 WebGPU 中使用 IBL&#xff08;基于图像的照明&#xff09;编写 PBR&#xff08;基于物理的渲染&#xff09;渲染器。 PBR 本身并没有什么新奇之处。 这是一项自 2014 年以来就存在的…

GeoServe Web 管理界面 实现远程访问

文章目录 前言1.安装GeoServer2. windows 安装 cpolar3. 创建公网访问地址4. 公网访问Geo Servcer服务5. 固定公网HTTP地址 前言 GeoServer是OGC Web服务器规范的J2EE实现&#xff0c;利用GeoServer可以方便地发布地图数据&#xff0c;允许用户对要素数据进行更新、删除、插入…