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

Vue中的Vue.nextTick的异步怎么实现

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

北京

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

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

看不清楚,换张图片

免费获取短信验证码

Vue中的Vue.nextTick的异步怎么实现

这篇文章主要介绍“Vue中的Vue.nextTick的异步怎么实现”,在日常操作中,相信很多人在Vue中的Vue.nextTick的异步怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue中的Vue.nextTick的异步怎么实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

Vue中的Vue.nextTick的异步怎么实现

一、nextTick小测试

你真的了解nextTick吗?来,直接上题~

<template>  <div id="app">    <p ref="name">{{ name }}</p>    <button @click="handleClick">修改name</button>  </div></template><script>  export default {  name: 'App',  data () {    return {      name: '井柏然'    }  },  mounted() {    console.log('mounted', this.$refs.name.innerText)  },  methods: {    handleClick () {      this.$nextTick(() => console.log('nextTick1', this.$refs.name.innerText))      this.name = 'jngboran'      console.log('sync log', this.$refs.name.innerText)      this.$nextTick(() => console.log('nextTick2', this.$refs.name.innerText))    }  }}</script>

请问上述代码中,当点击按钮“修改name”时,'nextTick1''sync log''nextTick2'对应的this.$refs.name.innerText分别会输出什么?注意,这里打印的是DOM的innerText~(文章结尾处会贴出答案)

如果此时的你有非常坚定的答案,那你可以不用继续往下看了~但如果你对自己的答案有所顾虑,那不如跟着我,接着往下看。相信你看完,不需要看到答案都能有个肯定的答案了~!


二、nextTick源码实现

源码位于core/util/next-tick中。可以将其分为4个部分来看,直接上代码

1. 全局变量

callbacks队列、pending状态

const callbacks = [] // 存放cb的队列let pending = false // 是否马上遍历队列,执行cb的标志

2. flushCallbacks

遍历callbacks执行每个cb

function flushCallbacks () {  pending = false // 注意这里,一旦执行,pending马上被重置为false  const copies = callbacks.slice(0)  callbacks.length = 0  for (let i = 0; i < copies.length; i++) {    copies[i]() // 执行每个cb  }}

3. nextTick的异步实现

根据执行环境的支持程度采用不同的异步实现策略

let timerFunc // nextTick异步实现fnif (typeof Promise !== 'undefined' && isNative(Promise)) {  // Promise方案  const p = Promise.resolve()  timerFunc = () => {    p.then(flushCallbacks) // 将flushCallbacks包装进Promise.then中  }  isUsingMicroTask = true} else if (!isIE && typeof MutationObserver !== 'undefined' && (  isNative(MutationObserver) ||  MutationObserver.toString() === '[object MutationObserverConstructor]')) {  // MutationObserver方案  let counter = 1  const observer = new MutationObserver(flushCallbacks) // 将flushCallbacks作为观测变化的cb  const textNode = document.createTextNode(String(counter)) // 创建文本节点  // 观测文本节点变化  observer.observe(textNode, {    characterData: true  })  // timerFunc改变文本节点的data,以触发观测的回调flushCallbacks  timerFunc = () => {     counter = (counter + 1) % 2    textNode.data = String(counter)  }  isUsingMicroTask = true} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {  // setImmediate方案  timerFunc = () => {    setImmediate(flushCallbacks)  }} else {  // 最终降级方案setTimeout  timerFunc = () => {    setTimeout(flushCallbacks, 0)  }}
  • 这里用个真实案例加深对MutationObserver的理解。毕竟比起其他三种异步方案,这个应该是大家最陌生的

    const observer = new MutationObserver(() => console.log('观测到文本节点变化'))const textNode = document.createTextNode(String(1))observer.observe(textNode, {    characterData: true})console.log('script start')setTimeout(() => console.log('timeout1'))textNode.data = String(2) // 这里对文本节点进行值的修改console.log('script end')
  • 知道对应的输出会是怎么样的吗?

    • script startscript end会在第一轮宏任务中执行,这点没问题

    • setTimeout会被放入下一轮宏任务执行

    • MutationObserver是微任务,所以会在本轮宏任务后执行,所以先于setTimeout

  • 结果如下图:
    Vue中的Vue.nextTick的异步怎么实现


4. nextTick方法实现

cbPromise方式

export function nextTick (cb?: Function, ctx?: Object) {  let _resolve  // 往全局的callbacks队列中添加cb  callbacks.push(() => {    if (cb) {      try {        cb.call(ctx)      } catch (e) {        handleError(e, ctx, 'nextTick')      }    } else if (_resolve) {      // 这里是支持Promise的写法      _resolve(ctx)    }  })  if (!pending) {    pending = true    // 执行timerFunc,在下一个Tick中执行callbacks中的所有cb    timerFunc()  }  // 对Promise的实现,这也是我们使用时可以写成nextTick.then的原因  if (!cb && typeof Promise !== 'undefined') {    return new Promise(resolve => {      _resolve = resolve    })  }}
  • 深入细节,理解pending有什么用,如何运作?

案例1,同一轮Tick中执行2次$nextTicktimerFunc只会被执行一次

this.$nextTick(() => console.log('nextTick1'))this.$nextTick(() => console.log('nextTick2'))
  • 用图看看更直观?

Vue中的Vue.nextTick的异步怎么实现


三、Vue组件的异步更新

这里如果有对Vue组件化派发更新不是十分了解的朋友,可以先戳这里,看图解Vue响应式原理了解下Vue组件化和派发更新的相关内容再回来看噢~

Vue的异步更新DOM其实也是使用nextTick来实现的,跟我们平时使用的$nextTick其实是同一个~

这里我们回顾一下,当我们改变一个属性值的时候会发生什么?

Vue中的Vue.nextTick的异步怎么实现

根据上图派发更新过程,我们从watcher.update开时讲起,以渲染Watcher为例,进入到queueWatcher

1. queueWatcher做了什么?

// 用来存放Wathcer的队列。注意,不要跟nextTick的callbacks搞混了,都是队列,但用处不同~const queue: Array<Watcher> = []function queueWatcher (watcher: Watcher) {  const id = watcher.id // 拿到Wathcer的id,这个id每个watcher都有且全局唯一  if (has[id] == null) {    // 避免添加重复wathcer,这也是异步渲染的优化做法    has[id] = true    if (!flushing) {      queue.push(watcher)    }    if (!waiting) {      waiting = true      // 这里把flushSchedulerQueue推进nextTick的callbacks队列中      nextTick(flushSchedulerQueue)    }  }}

2. flushSchedulerQueue做了什么?

function flushSchedulerQueue () {  currentFlushTimestamp = getNow()  flushing = true  let watcher, id  // 排序保证先父后子执行更新,保证userWatcher在渲染Watcher前  queue.sort((a, b) => a.id - b.id)  // 遍历所有的需要派发更新的Watcher执行更新  for (index = 0; index < queue.length; index++) {    watcher = queue[index]    id = watcher.id    has[id] = null    // 真正执行派发更新,render -> update -> patch    watcher.run()  }}
  • 最后,一张图搞懂组件的异步更新过程

Vue中的Vue.nextTick的异步怎么实现


四、回归题目本身

相信经过上文对nextTick源码的剖析,我们已经揭开它神秘的面纱了。这时的你一定可以坚定地把答案说出来了~话不多说,我们一起核实下,看看是不是如你所想!

如图所示,mounted时候的innerText是“井柏然”的中文

Vue中的Vue.nextTick的异步怎么实现

接下来是点击按钮后,打印结果如图所示

Vue中的Vue.nextTick的异步怎么实现

  • 没错,输出结果如下(意不意外?惊不惊喜?)

    • sync log 井柏然

    • nextTick1 井柏然

    • nextTick2 jngboran

  • 下面简单分析一下每个输出:

    this.$nextTick(() => console.log('nextTick1', this.$refs.name.innerText))this.name = 'jngboran'console.log('sync log', this.$refs.name.innerText)this.$nextTick(() => console.log('nextTick2', this.$refs.name.innerText))
    • sync log:这个同步打印没什么好说了,相信大部分童鞋的疑问点都不在这里。如果不清楚的童鞋可以先回顾一下EventLoop,这里不多赘述了~

    • nextTick1:注意其虽然是放在$nextTick的回调中,在下一个tick执行,但是他的位置是在this.name = 'jngboran'的前。也就是说,他的cb会App组件的派发更新(flushSchedulerQueue)更先进入队列,当nextTick1打印时,App组件还未派发更新,所以拿到的还是旧的DOM值。

    • nextTick2就不展开了,大家可以自行分析一下。相信大家对它应该是最肯定的,我们平时不就是这样拿到更新后的DOM吗?

  • 最后来一张图加深理解

Vue中的Vue.nextTick的异步怎么实现

到此,关于“Vue中的Vue.nextTick的异步怎么实现”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

免责声明:

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

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

Vue中的Vue.nextTick的异步怎么实现

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

下载Word文档

猜你喜欢

Vue中的Vue.nextTick的异步怎么实现

这篇文章主要介绍“Vue中的Vue.nextTick的异步怎么实现”,在日常操作中,相信很多人在Vue中的Vue.nextTick的异步怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue中的Vue.
2023-06-29

Vue Axios的异步通信怎么实现

这篇文章主要介绍了Vue Axios的异步通信怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue Axios的异步通信怎么实现文章都会有所收获,下面我们一起来看看吧。1.什么是AxiosAxios是一
2023-06-29

Vue中的同步调用和异步调用怎么实现

这篇“Vue中的同步调用和异步调用怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Vue中的同步调用和异步调用怎么实现
2023-06-28

python中的asyncio异步协程怎么实现

这篇“python中的asyncio异步协程怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“python中的async
2023-06-30

Python中怎么实现同步和异步

Python中怎么实现同步和异步,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。一、同步与异步#同步编程(同一时间只能做一件事,做完了才能做下一件事情) <-a
2023-06-17

怎么在JavaScript中实现同步和异步

本篇文章为大家展示了怎么在JavaScript中实现同步和异步,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。JavaScript可以做什么1.可以使网页具有交互性,例如响应用户点击,给用户提供更好的
2023-06-14

ADO.NET中怎么实现异步操作

ADO.NET中怎么实现异步操作,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。线程是允许程序的一部分独立于其他部分运行。线程可以在单个线程执行的同时运行多个操作,让用户感到像同
2023-06-17

VB.NET中怎么实现异步调用

这篇文章给大家介绍VB.NET中怎么实现异步调用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。VB.NET异步调用代码示例:private delegate Sub (()sub (or Function )()fu
2023-06-17

javascript怎么实现异步

JavaScript是一门常用的编程语言,被广泛应用于web开发、游戏开发等领域。在JavaScript编程中,异步编程是一项重要的技术,它能够提高程序的性能和响应速度。那么,JavaScript怎样实现异步编程呢?本篇文章将从以下方面进行说明。一、异步编程概述要深入了解JavaScript的异步编程,首先需要明确异步编程的概念。异步编程就是在程序执行某一动作时,同时可以执行其
2023-05-20

C++中怎么实现异步操作

C++中怎么实现异步操作,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。实现(代码)#include #include #include
2023-06-17

ASP.NET中怎么实现异步回调

ASP.NET中怎么实现异步回调,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。ASP.NET异步回调的重要性:在实际开发中,ASP.NET 客户端异步回调技术才是王道。下面我们
2023-06-17

WCF中怎么实现异步调用

这篇文章将为大家详细讲解有关WCF中怎么实现异步调用,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。随着时代的发展,异步调用在编程中是不可缺少的,这里就关于WCF异步调用简单的和大家分享一下吧
2023-06-17

编程热搜

  • 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动态编译

目录