我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

1 nextTick的用处

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

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

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

DOCTYPE html><html><head>    <title>Async Update Exampletitle>    <script class="lazy" data-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("开始");// 模拟一个异步函数,返回一个Promiseasync 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 = '

这是一个新的段落。

'
; }, 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)  }}

来源地址:https://blog.csdn.net/2201_75288929/article/details/132663663

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

vue的异步数据更新机制与$nextTick使用方法是什么

这篇文章主要讲解了“vue的异步数据更新机制与$nextTick使用方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue的异步数据更新机制与$nextTick使用方法是什么”吧!v
2023-07-05

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录