首页 > 语言 > JavaScript > 正文

详解从Vue.js源码看异步更新DOM策略及nextTick

2024-05-06 15:25:48
字体:
来源:转载
供稿:网友

写在前面

因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出。

文章的原地址:https://github.com/answershuto/learnVue。

在学习过程中,为Vue加上了中文的注释https://github.com/answershuto/learnVue/tree/master/vue-src,希望可以对其他想学习Vue源码的小伙伴有所帮助。

可能会有理解存在偏差的地方,欢迎提issue指出,共同学习,共同进步。

操作DOM

在使用vue.js的时候,有时候因为一些特定的业务场景,不得不去操作DOM,比如这样:

<template> <div> <div ref="test">{{test}}</div> <button @click="handleClick">tet</button> </div></template>
export default { data () {  return {   test: 'begin'  }; }, methods () {  handleClick () {   this.test = 'end';   console.log(this.$refs.test.innerText);//打印“begin”  } }}

打印的结果是begin,为什么我们明明已经将test设置成了“end”,获取真实DOM节点的innerText却没有得到我们预期中的“end”,而是得到之前的值“begin”呢?

Watcher队列

带着疑问,我们找到了Vue.js源码的Watch实现。当某个响应式数据发生变化的时候,它的setter函数会通知闭包中的Dep,Dep则会调用它管理的所有Watch对象。触发Watch对象的update实现。我们来看一下update的实现。

update () { /* istanbul ignore else */ if (this.lazy) {  this.dirty = true } else if (this.sync) {  /*同步则执行run直接渲染视图*/  this.run() } else {  /*异步推送到观察者队列中,下一个tick时调用。*/  queueWatcher(this) }}

我们发现Vue.js默认是使用异步执行DOM更新。

当异步执行update的时候,会调用queueWatcher函数。

 /*将一个观察者对象push进观察者队列,在队列中已经存在相同的id则该观察者对象将被跳过,除非它是在队列被刷新时推送*/export function queueWatcher (watcher: Watcher) { /*获取watcher的id*/ const id = watcher.id /*检验id是否存在,已经存在则直接跳过,不存在则标记哈希表has,用于下次检验*/ if (has[id] == null) { has[id] = true if (!flushing) {  /*如果没有flush掉,直接push到队列中即可*/  queue.push(watcher) } else {  // if already flushing, splice the watcher based on its id  // if already past its id, it will be run next immediately.  let i = queue.length - 1  while (i >= 0 && queue[i].id > watcher.id) {  i--  }  queue.splice(Math.max(i, index) + 1, 0, watcher) } // queue the flush if (!waiting) {  waiting = true  nextTick(flushSchedulerQueue) } }}

查看queueWatcher的源码我们发现,Watch对象并不是立即更新视图,而是被push进了一个队列queue,此时状态处于waiting的状态,这时候会继续会有Watch对象被push进这个队列queue,等待下一个tick时,这些Watch对象才会被遍历取出,更新视图。同时,id重复的Watcher不会被多次加入到queue中去,因为在最终渲染时,我们只需要关心数据的最终结果。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选