您的当前位置:首页正文

Vue—关于响应式(二、异步更新队列原理分析)

2024-08-03 来源:步旅网

有网友碰到这样的问题“Vue—关于响应式(二、异步更新队列原理分析)”。小编为您整理了以下解决方案,希望对您有帮助:

解决方案1:

本节学习要点:Event Loop、Promise

关于Event Loop的介绍,可以参考阮一峰老师的文章。

关于Promise,请访问:developer.mozilla.org/z...

上一节介绍了Vue通过Object.defineProperty拦截数据变化的响应式原理,数据变化后会触发notify方法来通知变更。这一节将继续分析,收到通知后Vue会开启一个异步更新队列。

以下是两个问题:

一、异步更新队列

首先看一段代码演示。

将上一节的代码拿过来,假设我们现在不仅依赖x,还有y、z,分别将x、y、z输出到页面上。我们现在依赖了x、y、z三个变量,那么我们应该把onXChange函数名改为watch,表示它可以监听变化,而不仅仅是监听一个x的变化。

可以看到这三个值都被打印在页面上。

现在我们对x、y、z的value进行修改。

查看页面,结果没有问题,每个数据的变化都被监听到并且进行了响应。

既然结果是对的,那我们的问题是什么?

这个问题是:每次数据变化都进行了响应,每次都渲染了模板,如果数据变化了一百次、一千次呢?难道要重复渲染一百遍、一千遍吗?

我们都知道频繁操作DOM会影响网页性能,涉及重排和重绘的知识感兴趣请阅读阮一峰老师的文章:ruanyifeng.com/blog/201...

因此,既要保证所有的依赖都准确更新,又要保证不能频繁渲染成为了首要问题。现在我们修改x.value、y.value、z.value都是同步通知依赖进行更新的,有没有一种机制可以等到我修改这些值之后再执行更新任务呢?

这个答案是——异步。

异步任务会等到同步任务清空后执行,借助这个特点和我们前面的分析,我们需要:

按照步骤,我们创建如下代码:

接着我们需要修改一下notify的代码,监听到数据变化后不立即调用依赖进行更新,而是将依赖添加到队列中。

回到页面,我们发现页面上还是重复渲染了三次模板。

那么我们写的这段代码有什么用呢?异步又体现在哪里呢?接着往下看。

二、nextTick原理分析

上面的代码中,虽然我们开启了一个队列,并且成功将任务推入队列中进行执行,但本质上还是同步推入和执行的。我们要让它变成异步队列。

于是到了Promise发挥作用的时候了。关于宏任务和微任务的介绍请参考:zhuanlan.zhihu.com/p/78...

我们创建nextTick函数,nextTick接收一个回调函数,返回一个状态为fulfilled的Promise,并将回调函数传给then方法。

然后只需要在添加任务时调用nextTick,将执行任务的flushJobs函数传给nextTick即可。

回到页面。

虽然修改了x、y、z三个变量的value,最后页面上只渲染了一次。

再来总结一下这段代码的执行过程:

这也正是Vue采用的解决方案——异步更新队列,官方文档描述得很清楚。

文档地址:cn.vuejs.org/v2/guide/r...

三、结合Vue源码来看nextTick

在Vue中,我们可以通过两种方式来调用nextTick:

(至于什么时候使用nextTick,如果你不偷懒看了官方文档的话,都能找到答案哈哈)

以下源码节选自vue2.6.11版本,这两个API分别在initGlobalAPI函数和renderMixin函数中挂载,它们都引用了nextTick函数。

nextTick源码如下:

在内部,它访问了外部的callbacks,这个callbacks就是前面提到的队列,nextTick一调用就给队列push一个回调函数,然后判断pending(pending的作用就是控制同一时间内只执行一次timerFunc),调用timerFunc(),最后返回了一个Promise(使用过nextTick的应该都知道吧)。

我们来看一下callbacks、pending、timerFunc是如何定义的。

可以看到timerFunc函数只是调用了p.then方法并将flushCallbacks函数推入了微任务队列,而p是一个fulfilled状态的Promise,与我们自己的nextTick功能一致。

这个flushCallbacks函数又干了什么呢?

flushCallbacks中重新将pending置为初始值,复制callbacks队列中的任务后将队列清空,然后依次执行复制的任务,与我们自己的flushJobs函数功能一致。

看完上面的源码,可以总结出Vue是这么做的,又到了小学语文之——提炼中心思想的时候了。

对比一下我们自己写的代码,你学会了吗?

以上演示代码已上传github:github.com/Mr-Jemp/VueS...

后面要学习的内容在这里:

Vue—关于响应式(三、Diff Patch原理分析)

Vue—关于响应式(四、深入学习Vue响应式源码)

本文由博客一文多发平台OpenWrite发布!

显示全文