当前位置:首页 > 科技  > 软件

解析$nextTick魔力,为啥大家都爱它?

来源: 责编: 时间:2024-01-02 09:31:13 349观看
导读1.为什么需要使用$nextTick?首先我们来看看官方对于$nextTick的定义:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。由于vue的试图渲染是异步的,生命周期的created()钩

1.为什么需要使用$nextTick?

首先我们来看看官方对于$nextTick的定义:KZx28资讯网——每日最新资讯28at.com

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。KZx28资讯网——每日最新资讯28at.com

由于vue的试图渲染是异步的,生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中,原因是在created()钩子函数执行的时候DOM其实并未进行渲染,而此时进行DOM操作是徒劳的,所以一定要将DOM操作的js代码放到Vue.nextTick()的回调函数中。除了在created()钩子函数中使用之外咱们还会遇到很多种需要使用到Vue.nextTick()的场景,如下所示:KZx28资讯网——每日最新资讯28at.com

咱们日常生活中常常会遇上上述场景,当我们点击按钮更新数据时候,如下示例:KZx28资讯网——每日最新资讯28at.com

<template>    <div>     <input type="text" v-if = "isShow" ref="input"/>     <button @click="handleClick">点击显示输入框,并且获取输入框焦点</button>   </div></template><script>export default { data() {     return {         isShow: false       } }, methods : { handleClick () {     this.isShow = true     this.$refs.input.focus() //控制栏会报错,因为还没有这个dom        }  }}</script>

点击控制栏显示效果:控制栏报错,提示没有获取到dom元素;KZx28资讯网——每日最新资讯28at.com

KZx28资讯网——每日最新资讯28at.com

所以现在Vue.nextTick()派上了用场,Vue.nextTick() 方法的作用正是等待上一次事件循环执行完毕,并在下一次事件循环开始时再执行回调函数。这样可以保证回调函数中的 DOM 操作已经被 Vue.js 进行过更新,从而避免了一些潜在的问题,如下代码所示:KZx28资讯网——每日最新资讯28at.com

<template>  <div>    <input type="text" v-if = "isShow" ref="input"/>    <button @click="handleClick">点击显示输入框,并且获取输入框焦点</button>  </div></template><script>export default { data() {   return {     isShow: false   } }, methods : {   handleClick () {     this.isShow = true     this.$nextTick(()=>{       this.$refs.input.focus()      })    } }}</script>

加上this.$nextTick后就能够使得输入框获取到焦点;KZx28资讯网——每日最新资讯28at.com

总而言之Vue.nextTick()就是下次 DOM 更新渲染后执行延迟回调函数。在日常开发中,我们在修改数据之后使用这个方法,就可以获取更新后的 DOM的同时进行在对DOM进行相对应操作的 js代码;KZx28资讯网——每日最新资讯28at.com

2.$nextTick如何实现的?

JS是单线程执行的,所有的同步任务都是在主线程上执行的,形成了一个执行栈,从上到下依次执行,异步代码会放在任务队列里面。KZx28资讯网——每日最新资讯28at.com

•同步任务KZx28资讯网——每日最新资讯28at.com

在主线程里执行,当浏览器第一遍过滤html文件的时候可以执行完;(在当前作用域直接执行的所有内容,包括执行的方法、new出来的对象)KZx28资讯网——每日最新资讯28at.com

•异步任务KZx28资讯网——每日最新资讯28at.com

耗费时间较长或者性能较差的,浏览器执行到这些的时候会将其丢到异步任务队列中,不会立即执行KZx28资讯网——每日最新资讯28at.com

同时异步任务分为宏任务(如setTimeout、setInterval、postMessage、setImmediate等)和微任务(Promise、process.nextTick等),浏览器执行这两种任务的优先级不同;会优先执行微任务队列的代码,微任务队列清空之后再执行宏任务的队列,这样循环往复;KZx28资讯网——每日最新资讯28at.com

JS自上向下进行代码的编译执行,遇到同步代码压入JS执行栈执行后出栈,遇到异步代码放入任务队列,当JS执行栈清空,去执行异步队列中的回调函数,先去执行微任务队列,当微任务队列清空后,去检测执行宏任务队列中的回调函数,直至所有栈和队列清空KZx28资讯网——每日最新资讯28at.com

整体流程如下图所示:KZx28资讯网——每日最新资讯28at.com

KZx28资讯网——每日最新资讯28at.com

KZx28资讯网——每日最新资讯28at.com

KZx28资讯网——每日最新资讯28at.com

接下来让我们看看nextTick的源码~KZx28资讯网——每日最新资讯28at.com

vue将nextTick的源码放在了vue/core/util/next-tick.js中。如下图所示:KZx28资讯网——每日最新资讯28at.com

KZx28资讯网——每日最新资讯28at.com

KZx28资讯网——每日最新资讯28at.com

我们把这个文件拆成三个部分来看:KZx28资讯网——每日最新资讯28at.com

1.nextTick定义函数

我们将nextTick函数单独拿出来,callbacks是一个回调队列,其实调用nextTick就是往这个数组里面传执行任务,callbacks新增回调函数之后执行timerFunc函数,pending是用来限制同一个事件循环内只能执行一次的pending锁;KZx28资讯网——每日最新资讯28at.com

const callbacks = [] // 回调队列let pending = false // export function nextTick (cb?: Function, ctx?: Object) { let _resolve callbacks.push(() => {  // cb 回调函数会经统一处理压入 callbacks 数组     if (cb) {         try {             cb.call(ctx)         } catch (e) {             handleError(e, ctx, 'nextTick')         }     } else if (_resolve) {         _resolve(ctx)        }     })  // 执行异步延迟函数 timerFunc     if (!pending) {     pending = true     timerFunc() } // $flow-disable-line // 当 nextTick 没有传入函数参数的时候,返回一个 Promise 化的调用if (!cb && typeof Promise !== 'undefined') {     return new Promise(resolve => {     _resolve = resolve     }) }}

2.timerFunc函数

 做了四个判断,先后尝试当前环境是否能够使用原生的Promise.then、MutationObserver和setImmediate,不断的降级处理,如果以上三个都不支持,则最后就会直接使用setTimeOut,主要操作就是将flushCallbacks中的函数放入微任务或者宏任务,等待下一个事件循环开始执行;宏任务耗费的时间是大于微任务的,所以在浏览器支持的情况下,优先使用微任务。如果浏览器不支持微任务,使用宏任务;但是,各种宏任务之间也有效率的不同,需要根据浏览器的支持情况,使用不同的宏任务;KZx28资讯网——每日最新资讯28at.com

export let isUsingMicroTask = falselet timerFuncif (typeof Promise !== 'undefined' && isNative(Promise)) { //是否支持Promise const p = Promise.resolve() timerFunc = () => { p.then(flushCallbacks)  if (isIOS) setTimeout(noop) } isUsingMicroTask = true} else if (!isIE && typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || MutationObserver.toString() === '[object MutationObserverConstructor]')) {//是否支持MutationObserver  let counter = 1 const observer = new MutationObserver(flushCallbacks) const textNode = document.createTextNode(String(counter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) } isUsingMicroTask = true} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { timerFunc = () => {  //是否支持setImmediate setImmediate(flushCallbacks) }} else { // Fallback to setTimeout. timerFunc = () => {  //上面都不行,直接使用setTimeout setTimeout(flushCallbacks, 0) }}

3.flushCallbacks函数

flushCallbacks函数只有几行,也很好理解,将pending锁置为false,同时将callbacks数组复制一份之后再将callbacks置为空,接下来将复制出来的callbacks数组的每个函数依次进行执行,简单来说它的主要作用就是用来执行callbacks中的回调函数;KZx28资讯网——每日最新资讯28at.com

function flushCallbacks () { pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) {     copies[i]() }}

值得注意的是,$nextTick 并不是一个真正意义上的微任务microtask,而是利用了事件循环机制来实现异步更新。因此,它的执行时机相对于微任务可能会有所延迟,但仍能保证在 DOM 更新后尽快执行回调函数。KZx28资讯网——每日最新资讯28at.com

总的来说,nextTick就是KZx28资讯网——每日最新资讯28at.com

1.将传入的回调函数放入callbacks数组等待执行,定义pending判断锁保证一个事件循环中只能调用一次timerFunc函数;KZx28资讯网——每日最新资讯28at.com

2.根据环境判断使用异步方式,调用timerFunc函数调用flushCallbacks函数依次执行callbacks中的回调函数;KZx28资讯网——每日最新资讯28at.com

3.个人小结

nextTick可避免数据更新后导致DOM的数据不一致的问题,提供了更稳定的异步更新机制,解决了created钩子函数DOM未渲染会造成的异步数据渲染问题,但如果过多的使用nextTick会导致事件循环中任务数量和回调函数增多,有可能出现可怕的回调地狱,导致性能下降,同时过度依赖nextTick也会降低代码的可读性,所以大家还是"按需加载"的好~KZx28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-55186-0.html解析$nextTick魔力,为啥大家都爱它?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 解析$nextTick魔力,为啥大家都爱它?

下一篇: 浅谈B站效果广告在线推理服务的性能优化

标签:
  • 热门焦点
  • 2023年Q2用户偏好榜:12+256G版本成新主流

    3月份的性能榜、性价比榜和好评榜之后,就要轮到2023年的第二季度偏好榜了,上半年的新机潮已经过去,最明显的肯定就是大内存和存储的机型了,另外部分中端机也取消了屏幕塑料支架
  • 5月安卓手机好评榜:魅族20 Pro夺冠

    性能榜和性价比榜之后,我们来看最后的安卓手机好评榜,数据来源安兔兔评测,收集时间2023年5月1日至5月31日,仅限国内市场。第一名:魅族20 Pro好评率:97.50%不得不感慨魅族老品牌还
  • K8S | Service服务发现

    一、背景在微服务架构中,这里以开发环境「Dev」为基础来描述,在K8S集群中通常会开放:路由网关、注册中心、配置中心等相关服务,可以被集群外部访问;图片对于测试「Tes」环境或者
  • 如何正确使用:Has和:Nth-Last-Child

    我们可以用CSS检查,以了解一组元素的数量是否小于或等于一个数字。例如,一个拥有三个或更多子项的grid。你可能会想,为什么需要这样做呢?在某些情况下,一个组件或一个布局可能会
  • 三分钟白话RocketMQ系列—— 如何发送消息

    我们知道RocketMQ主要分为消息 生产、存储(消息堆积)、消费 三大块领域。那接下来,我们白话一下,RocketMQ是如何发送消息的,揭秘消息生产全过程。注意,如果白话中不小心提到相关代
  • 零售大模型“干中学”,攀爬数字化珠峰

    文/侯煜编辑/cc来源/华尔街科技眼对于绝大多数登山爱好者而言,攀爬珠穆朗玛峰可谓终极目标。攀登珠峰的商业路线有两条,一是尼泊尔境内的南坡路线,一是中国境内的北坡路线。相
  • 小米MIX Fold 3下月亮相:今年唯一无短板的全能折叠屏

    这段时间以来,包括三星、一加、荣耀等等有不少品牌旗下的最新折叠屏旗舰都有新的进展,其中荣耀、三星都已陆续发布了最新的折叠屏旗舰,尤其号荣耀Magi
  • 三星获批量产iPhone 15全系屏幕:苹果史上最惊艳直屏

    按照惯例,苹果将继续在今年9月举办一年一度的秋季新品发布会,有传言称发布会将于9月12日举行,届时全新的iPhone 15系列将正式与大家见面,不出意外的话
  • 三星折叠屏手机去年销售近1000万台 今年目标定为1500万

    7月29日消息,三星率先发力可折叠手机市场,在全球市场已经取得了非常亮眼的成绩,接下来会进一步巩固和扩大这一优势。三星在推出Galaxy Z Flip5和Galax
Top