简单易懂 关于nextTick()的理解
Posted Deca~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单易懂 关于nextTick()的理解相关的知识,希望对你有一定的参考价值。
前言
学习Vue的过程中,大家肯定都使用过nextTick(),关于nextTick()的使用时机,大家肯定都知道,那么它的工作原理是怎样的呢,本文就简单说一下它的nextTick()的工作原理。
nextTick的使用时机
首先记住:nextTick所指定的回调会在浏览器更新DOM完毕之后再执行。
举个例子:
在我自己做的一个单页面应用中,我有一个需求,当从后端请求回数据后,马上就对页面进行更新。比如,我要点击操作里的删除操作,前端删除数据后就向后端发请求,后端删除数据后返回数据,如果我们想马上显示到页面上,应该怎么做呢?
可能好多人会像我第一次做那样,比如我这个页面是用 v-for 遍历data这个数据显示出来的,可能好多人就会直接把前端返回的数据直接重新赋值给data。但是这样是绝对不行的!这样只会导致数据其实是变了,但是视图是不会变的,因为vue更新dom是异步的,无法通过同步代码赋值后马上去更新页面。所以即使删除成功了页面也不会显示出来。即使显示删除成功,页面也不会更新。
如何更新
我们的需求是,请求回数据后马上更新页面,首先理解几个点。
1、vue更新Dom是异步更新。
如图官网的描述,解释一下这段话,直接看可能有些懵,前两句话,关于同步和异步,以及提到的"事件循环",这就要从JS的运行机制说起,戳我前往。第三句话,“如果同一个 watcher 被多次触发,只会被推入到队列中一次”,这是什么意思呢,也在我的文章中可找到,戳我前往。
2、理解执行时机
读完上面两篇文章,大家应该就知道宏任务和微任务了把,而nextTick内部就是调用宏任务和微任务来完成事件调用的机制,让nextTick里的回调在一个事件循环的最后执行。为什么要在最后呢?在最后即意味着在所有异步任务之后,记得上一点吗,“vue更新Dom是异步更新”,而我们又把nextTick里的回调放在了所有异步任务的最后,这样就解释了最开始那句话,nextTick所指定的回调会在浏览器更新DOM完毕之后再执行。
3、回到例子实现需求
我们想要实现需求,本例我们采用热更新,即只更新局部组件。
我直接把我的子组件全放在router-view里的,通过变化v-if来实现组件更新。
看到这里可能有人会问,这不就是先把v-if设为false,再设置为true来实现吗,要不要nextTick都一样,那么这样想就大错特错了。
还记得刚才说的“如果同一个 watcher 被多次触发,只会被推入到队列中一次”,那篇文章已经解释过了,vue会把所有代码都执行了再去渲染页面,所以我们这两条this.$isRouterAlive = false 和 this.$isRouterAlive = true,相当于只执行了最后一条等于true,false都没执行过,所以相当于还是什么都没做,原始是true,现在还是true。
加了个nextTick就不一样了,这段代码就相当于告诉vue,vue你先帮我执行 this.$isRouterAlive = false,先不要管我nextTick里的东西,你去渲染完了最后再来执行我nextTick里的代码。
这样一说大家是不是就比较明白了,this.$isRouterAlive = true 是在页面渲染过后 再执行的,所以我们肉眼看其实已删除货物,页面马上就更新了,其实其中经过了先把router-view里的子组件取消掉,即v-if = false,然后再让 v-if = true,那么v-if大家都知道就是创建,相当于router-view里的内容被重新创建了,所以此时的数据也是最新的。
关于nextTick的理解
首先先看一下官方的解释:
this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
我的理解:在this.$nextTick外面,获取的数据有可能已经改变了但是获取的时候还是之前的值,但是在this.$nextTick里面只要获取的数据发生改变,获取的时候就是改变了之后的数据
具体看代码吧
<template> <section> <div ref="hello"> <!-- 绑定了data里面的值并渲染到页面--> <h1 v-model="msg">{{msg}}</h1> </div> </section> </template> <script> export default { data(){ return { msg:‘123123‘ } }, mounted() { this.msg=‘456456‘ console.log(333); console.log(this.$refs.hello.innerText); this.$nextTick(() => { console.log(444); console.log(this.$refs.hello.innerText); }); },
运行结果可以知道:
在333之前改变了msg的值,但是获取表单数据的时候还是之前的123123
但是在nextTick里面获取的时候就发生了改变
且表单渲染的结果也是更新之后的
具体原因是由于,将msg改变值之后们虽然数据层发生了变化,但是dom层未更新,但是nexttick里面会在dom更新之后立马使用,所以得到的数据就是比较新的数据。
下面说一下JS的宏任务和微任务
微任务micro task: MutationObsever 和 Promise.then
在vue2.5之后哦的版本,nextTick就属于宏任务了
测试代码:
created() { //ref 需要在dom渲染完成后才会有,在使用的时候确保dom已经渲染完成。 // 比如在生命周期 mounted(){} 钩子中调用,或者在 this.$nextTick(()=>{}) 中调用 console.log(111); console.log(this.$refs.hello); this.$nextTick(() => { console.log(222); console.log(this.$refs.hello); }); var promise= new Promise(function (resolve,reject) { console.log(888) }) console.log(promise) },
测试结果:
出现这样的结果是因为:
先执行主线程的任务,当主线程的任务执行完了之后,由于promise是微任务,nextTick是宏任务,微任务的优先级要高于宏任务,所以会先执行微任务里面的内容,等到微任务执行完了之后在执行宏任务内容
以上是关于简单易懂 关于nextTick()的理解的主要内容,如果未能解决你的问题,请参考以下文章