Vue.js 依赖收集

本贴最后更新于 2674 天前,其中的信息可能已经时过境迁

写在前面

因为对 Vue.js 很感兴趣,而且平时工作的技术栈也是 Vue.js,这几个月花了些时间研究学习了一下 Vue.js 源码,并做了总结与输出。
文章的原地址:https://github.com/answershuto/learnVue
在学习过程中,为 Vue 加上了中文的注释 https://github.com/answershuto/learnVue/tree/master/vue-src,希望可以对其他想学习 Vue 源码的小伙伴有所帮助。
可能会有理解存在偏差的地方,欢迎提 issue 指出,共同学习,共同进步。

依赖收集是在响应式基础上进行的,不熟悉的同学可以先了解《响应式原理》

为什么要依赖收集

先看下面这段代码

new Vue({

template:

`

text1: {{text1}}

text2: {{text2}}

`,

data: {

text1: 'text1',

text2: 'text2',

text3: 'text3'

}

});

按照之前《响应式原理》中的方法进行绑定则会出现一个问题——text3 在实际模板中并没有被用到,然而当 text3 的数据被修改的时候(this.text3 = 'test')的时候,同样会触发 text3 的 setter 导致重新执行渲染,这显然不正确。

先说说 Dep

当对 data 上的对象进行修改值的时候会触发它的 setter,那么取值的时候自然就会触发 getter 事件,所以我们只要在最开始进行一次 render,那么所有被渲染所依赖的 data 中的数据就会被 getter 收集到 Dep 的 subs 中去。在对 data 中的数据进行修改的时候 setter 只会触发 Dep 的 subs 的函数。

定义一个依赖收集类 Dep。

class Dep () {

constructor () {

this.subs = [];

}

addSub (sub: Watcher) {

this.subs.push(sub)

}

removeSub (sub: Watcher) {

remove(this.subs, sub)

}

notify () {

// stabilize the subscriber list first

const subs = this.subs.slice()

for (let i = 0, l = subs.length; i < l; i++) {

subs[i].update()

}

}

}

Watcher

订阅者,当依赖收集的时候回 addSub 到 sub 中,在修改 data 中数据的时候会触发 Watcher 的 notify,从而回调渲染函数。

class Watcher () {

constructor (vm, expOrFn, cb, options) {

this.cb = cb;

this.vm = vm;

/在这里将观察者本身赋值给全局的 target,只有被 target 标记过的才会进行依赖收集/

Dep.target = this;

/触发渲染操作进行依赖收集/

this.cb.call(this.vm);

}

update () {

this.cb.call(this.vm);

}

}

开始依赖收集

class Vue {

constructor(options) {

this._data = options.data;

observer(this._data, options.render);

let watcher = new Watcher(this, );

}

}

function defineReactive (obj, key, val, cb) {

在闭包内存储一个 Dep 对象

const dep = new Dep();

Object.defineProperty(obj, key, {

enumerable: true,

configurable: true,

get: ()=>{

if (Dep.target) {

/Watcher 对象存在全局的 Dep.target 中/

dep.addSub(Dep.target);

}

},

set:newVal=> {

/只有之前 addSub 中的函数才会触发/

dep.notify();

}

})

}

Dep.target = null;

将观察者 Watcher 实例赋值给全局的 Dep.target,然后触发 render 操作只有被 Dep.target 标记过的才会进行依赖收集 。有 Dep.target 的对象会讲 Watcher 的实例 push 到 subs 中,在对象被修改出发 setter 操作的时候 dep 会调用 subs 中的 Watcher 实例的 update 方法进行渲染。

  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    265 引用 • 666 回帖
  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    728 引用 • 1273 回帖
  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    247 引用 • 1348 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...