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

news2024/12/23 23:28:24

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) {
            // 遍历变化列表中的每个MutationRecord
            for (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 = false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (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 = 1
  const observer = new MutationObserver(flushCallbacks)
  const textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {
    characterData: true
  })
  //这种情况下,timerFunc 将观察一个文本节点的字符数据变化来触发回调函数的执行
  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)
  }
}

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

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

相关文章

vscode+esp-idf 搭建esp32开发环境,编译信息中文乱码

1.修改波特率 2.C:\Users\Administrator\.vscode\extensions\vsciot-vscode.vscode-arduino-0.6.0-win32-x64\out\src\common 打开文件 util.js 屏蔽掉这部分的代码 、

献给前端研发同学的福利!性能诊断神器——Chrome Performance insight!

Performance insight概述 Performance insight是chrome Chrome DevTools中的自带工具&#xff08;Chrome102 版本发布&#xff09;&#xff0c;目前还是在chrome DevTool中启动即可&#xff0c;如下图所示&#xff1a;我们可以模拟cpu&#xff0c;选择4x slowdown&#xff0c;…

大数据可视化大屏实战项目(8)史上最炫酷科技风销售额度展示大屏,适用于电子产品---HTML+CSS+JS【源码在文末】(可用于比赛项目或者作业参考中)

大数据可视化大屏实战项目&#xff08;8&#xff09;史上最炫酷科技风销售额度展示大屏&#xff0c;适用于电子产品—HTMLCSSJS【源码在文末】&#xff08;可用于比赛项目或者作业参考中&#x1f415;&#x1f415;&#x1f415;&#xff09; 一&#xff0c;项目概览 ☞☞☞☞…

发生OOM时JVM会退出吗

程序是否退出和发生 OOM 无关 需要明确&#xff0c;程序是否退出和发生 OOM 无关&#xff0c;而和当前是否还有存活的非守护线程有关。 只要还有运行中的子线程&#xff0c;即使 main 线程结束或异常崩溃了&#xff0c;程序也不会停止。 public class TestThreadRun {privat…

管理类联考——逻辑——汇总篇——知识点突破——论证逻辑——论证模型

不同的模型对应的削弱、支持、假设。 归纳模型 模型识别 1.完全归纳 完全归纳指的就是所谓的穷举法&#xff0c;即通过某一类对象中的全部元素具备或者不具备某个性质&#xff0c;从而证明这一类对象都具备或者不具备某个性质。考试中一般不考察完全归纳&#xff0c;因此&am…

彻底了解 npm、cnpm、pnpm 、yarn几种包管理工具

npm、cnpm、pnpm 、yarn几种包管理工具 npmcnpmyarnpnpm四者的优缺点&#xff1a; npm npm 是 Node.js 自带的包管理器&#xff0c;平时通过 npm install 命令来安装各种 npm 包&#xff08;比如&#xff1a;npm install vue-router &#xff09;&#xff0c;就是通过这个包管…

基于OpenEuler的信创国产瘦客户机软件系统 DoraOS

DoraOS是一款瘦客户机系统软件&#xff0c;最新版本基于OpenEuler开发。可以将主机转化为专业的瘦客户机。目前支持x86架构的硬件。 软件下载地址为&#xff1a; https://www.doracloud.cn/downloads/32-cn.html 制作一张启动U盘&#xff0c;即可进行安装。 DoraOS的连接窗口…

3D数据导出工具HOOPS Publish:3D数据查看、生成标准PDF或HTML文档!

HOOPS中文网http://techsoft3d.evget.com/ 一、3D导出SDK HOOPS Publish是一款功能强大的SDK&#xff0c;可以创作丰富的工程数据并将模型文件导出为各种行业标准格式&#xff0c;包括PDF、STEP、JT和3MF。HOOPS Publish核心的3D数据模型是经过ISO认证的PRC格式(ISO 14739-1:…

【UIPickerView案例04-随机点餐完善 Objective-C语言】

一、之前我们讲到哪里 1)首先,是搭建界面 2)然后呢,是加载数据 先把这个数据文件,拖进来,然后呢,设置它的代理对象、数据源对象 然后呢,在控制器里面,遵守对应的协议, 实现对应的方法 跟TableView的思路,一样一样的, 也是,把多少行返回 把多少组,返回 然后呢…

【python爬虫】12.建立你的爬虫大军

文章目录 前言协程是什么多协程的用法gevent库queue模块 拓展复习复习 前言 照旧来回顾上一关的知识点&#xff01;上一关我们学习如何将爬虫的结果发送邮件&#xff0c;和定时执行爬虫。 关于邮件&#xff0c;它是这样一种流程&#xff1a; 我们要用到的模块是smtplib和emai…

WordPress Page Builder KingComposer 2.9.6 Open Redirection

WordPress Page Builder KingComposer 2.9.6 Open Redirection WordPress 插件 KingComposer 版本2.9.6 以及以前版本受到开放重定向漏洞的影响。该漏洞在packetstorm网站披露于2023年7月24日&#xff0c;除了该漏洞&#xff0c;该版本的插件还存在XSS攻击的漏洞风险 图1.来自…

【无源谐波滤波器通常用于电力系统中的谐波抑制】用于抑制电力系统谐波的无源谐波滤波器(Simulink实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

十年AI技术成果加持,猿辅导带你体验网课中的科技感

近年来&#xff0c;AI正以润物细无声的方式重塑多个行业的面貌&#xff0c;教育行业也不例外。同时&#xff0c;随着Chat GPT对社会带来的冲击不断加强&#xff0c;AI教育已经成为整个行业不可逆转的趋势。作为最早踏入智能教育领域的企业之一&#xff0c;猿辅导深谙技术革新对…

揭秘大企业的在线帮助中心搭建都有什么技巧?

大企业的在线帮助中心是为了提供更好的客户支持和服务而设立的一个重要平台。一个优秀的在线帮助中心可以帮助企业有效地解决客户问题、提高客户满意度&#xff0c;并且节省人力资源。 搭建大企业在线帮助中心的技巧&#xff1a; 设计用户友好的界面&#xff1a;在线帮助中心…

OPPO手机便签数据搬家到华为mate60Pro手机怎么操作

今年8月底&#xff0c;华为上线了本年度的旗舰手机——华为mate60Pro。有不少网友都在抢购这台手机&#xff0c;不过在拿到新手机之后&#xff0c;还有一件重要的事情要做&#xff0c;这就是把旧手机中比较重要的数据&#xff0c;例如图片、短信、通讯录、联系人、便签等数据搬…

13 PyQt5控件之QTreeWidget

目录 1 官方帮助文档2 基本使用3 模型事件 1 官方帮助文档 QTreeWidget Qt5.15帮助文档 2 基本使用 #!/usr/bin/python3 # -*- coding: GBK -*-import sys from PyQt5.QtCore import QSize from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import *class QTreeWidgetDe…

计算机毕设之基于python+django+mysql数据可视化的智慧社区内网平台(包含文档+源码+部署教程)

系统阐述的是一款基于数据可视化的智慧社区内网平台的设计与实现&#xff0c;对于Python、B/S结构、MySql进行了较为深入的学习与应用。主要针对系统的设计&#xff0c;描述&#xff0c;实现和分析与测试方面来表明开发的过程。开发中使用了 django框架和MySql数据库技术搭建系…

xxl-job 任务调度搭建及简单使用

xxl-job是开源架构&#xff0c;可以通过它实现调度中心和执行器。 git地址和 官网中进行了详细的技术说明。   xxl-job支持单机部署和集群式部署&#xff0c;在集群式部署中又可以实现调度中心集群式部署和执行器集群式部署。本文主要针对调度中心和执行器分离单机部署方式进…

因为axios请求后端,接收不到token的问引出的问题

vue axios请求后端接受不到token的问题。 相关概念 什么是跨域&#xff1f; 跨域指的是在浏览器环境下&#xff0c;当发起请求的域&#xff08;或者网站&#xff09;与请求的资源所在的域之间存在协议、主机或端口中的任何一个条件不同的情况。换句话说&#xff0c;只要协议、…

java八股文面试[JVM]——如何打破双亲委派模型

双亲委派模型的第一次“被破坏”是重写自定义加载器的loadClass(),jdk不推荐。一般都只是重写findClass()&#xff0c;这样可以保持双亲委派机制.而loadClass方法加载规则由自己定义&#xff0c;就可以随心所欲的加载类&#xff0c;典型的打破双亲委派模型的框架和中间件有tomc…