美文网首页
vue知识点-1--变化侦测-依赖收集

vue知识点-1--变化侦测-依赖收集

作者: 前端劝退师_ty | 来源:发表于2019-12-24 13:09 被阅读0次

本文相当于笔记,最近在看深入浅出vue.js的记录,需要配合书一起看,如果你也在看这本书可以一起看看这篇文章,不然会看不懂。
vue 在运行是内部的状态不断改变,页面不停的重新渲染,想要达到这样的变化侦测效果第一步就要解决依赖收集的部分。
依赖收集就是记录哪些数据用到了哪些地方,这样在变化的时候就能去精准的通知其去改变。

大体思路就是用Object.defineProperty 设置get、set监听到数据的读取和改变,在get中收集依赖,在set通知收集到的依赖去改变。

Dep收集依赖的地方,可以叫做存储位置

封装一个Dep类管理依赖收集的地方(depend依赖 的缩写,为每个属性都new 一个Dep类,每个属性都有自己对于的依赖收集的地方)
Dep类中 主要的结构
this.subs = [] (subscribe 订阅 缩写)这个数组就是用来收集具体哪里调用的该属性,
depend()函数 push进subs中 就是添加依赖的,判断window.target是否有值 如果有假加入到subs中(window.target)是全局变量
notify()函数 用于更新所有的依赖 里面就是一个循环调用subs的update方法

defineReactive()收集和触发依赖动作

defineReactive() 是个方法 里面封装了 Object.defineProperty 统一设置了get,set为每一个属性,get中收集, set中触发更新

先是调用了observe() 传递进入val
let childOb = observe(val)
这个函数内部判断了是否是对象如果是不是对象就返回空(数组也是对象哦,typeof)
不是对象,有个过滤的机制避免重复侦测,根据__ob__
过滤后调用真正的Observe 该类主要功能是循环对象递归调用defineReactive使其每个属性都具备get,set也就是有收集和触发的功能,Observe是个类 childOb拿到的是他的实例
Observe稍后介绍继续说defineReactive

实例化了let dep = new Dep()

在get中调用了 dep.depend() 以及 childOb.dep.depend()
这么写是为了统一在get中进行依赖收集 childOb 是用来处理 数组的依赖收集,
数组和对象的依赖收集都是一样的 list:[] 要读取这个数组 就要先找到list 肯定会触发list的get
数组的操作方法,push shift 这些改变数组的方法不能触发getter/setter,数组用的是重写覆盖原始的Array原型方法这样就知道了用户操作了那些方法,以这种形式来收集和触发依赖,这也被叫做拦截器

set中调用 dep.notify()

Watcher类 数据变化通知的地方 可以看做vue中的$watch

get()方法 这里很厉害,把this 赋值给全局变量 window.target 然后再去读取对应的数据,这样就触发了上一步写的 defineReactive 中设置好的get get中调用dep.depend(), depend把window.target 加入到 subs数组中,用于以后更改时update,这样就顺利的把前后链接了起来
update()方法 上面说的 notify会循环调用数据的更新就是这里的update方法,该方法里是$watch时写的回调用call保持上下文关系执行,
所以每次声明watch的时候会在constructor中调用this.get(),就可以主动的把this添加到dep中,很神奇。

Observer()递归侦测所有属性

主要用于循环数据下面的所有属性让每个属性都有收集和通知的能力,这其中也处理了数组的原型覆盖,

实例了dep 用于数据依赖收集的

给每个数据加上了一个不可枚举的__ob__标识,这个标识就是this,主要是两个作用,
1、用于过滤判断当前属性是否已经被侦测变化,
2、数组是侦测变化是改写原型上的方法,原型上从this直接拿到__ob__就是Observer的实例,实例上有dep 当触发了改写的push后就能去调用dep 中的notify()
这里很巧妙,收集是在defineReactive的get中 调用是在 原型的方法中,Observer相当于是中间的位置,上下都能拿到

如果是对象就循环递归调用 defineReactive

判断如果是数组重新赋值他的__proto__, __proto__指向的是实例他的原型,也就是一个对象,所以生成一个对象就好,这个对象以Array.prototype作为基础在上面改写,要保证数据传进来调用 Array.prototype 同样的方法做处理,返回同样的返回值,然后在这其中加入收集和通知就ok了,
arrayMethods = Object,creare(Array.prototype);
只改写了push pop shift unshift splice sort reverse 一共七个可以改变自身的方法,
用defineProperty改写,在value中 用 apply保持上下文并且把 ...args传入进去 让其拥有原本的功能并且返回一样的值,
额外的操作 let ob = this.__ob __;这个是Observer的实例,里面有dep,调用dep.notify()让其更新,
如果使用的是push unshift splice 这三,他们是可以在数组中新增元素的,新增的元素要保持可以侦测变化,同样是调用ob上的方法,observeArray

observeArray 循环传递进来的数组,调用observe,又回来了,---是对象就循环递归调用 defineReactive ,是数组覆盖__proto__

以上这些大致就是变化侦测的基本实现

了解了原理也就知道了为什么vue中一些数据的变化是不能更新的。
this.list[0] = 1;
observe 数组中循环时对象通过,否则不会赋予收集和通知的功能。数组中是个值是不能监测变化的是对象可以。
list.length = 0
vue在处理是根本没有这个回调,所以这样使用时都不知道数组变化了。
delete this.obj.name这样的操作是不能追踪变化的,因为defineProperty 的set 只能知道数据是否被更改不能知道数据是否被删除或是新增。不过也有配套的api解决这个问题 vue.set , vue.delete

相关文章

  • vue知识点-1--变化侦测-依赖收集

    本文相当于笔记,最近在看深入浅出vue.js的记录,需要配合书一起看,如果你也在看这本书可以一起看看这篇文章,不然...

  • 深入浅出 - vue变化侦测原理

    深入浅出 - vue变化侦测原理 关于vue的内部原理其实有很多个重要的部分,变化侦测,模板编译,virtualD...

  • vue侦测数据变化

    如何使用watch侦听数据变化?如何通过计算属性computed配合watch属性来侦听数据变化?深度侦听与单一属...

  • Vue实例简单实现

    简单实现vue框架实例,实现的目的主要看下几个知识点如何进行的: Vue工作机制 Vue响应式的原理 依赖收集与追...

  • Vue2源码解析系列

    目录 Vue整体流程一(带你了解一下Vue源码) 变化侦测篇(Observer) 虚拟DOM篇(VNode) 模板...

  • Object的变化侦测

    1.1 什么是变化侦测 vue.js会自动通过状态生成DOM,并将其输出到页面显示,这个过程叫渲染。vue.js的...

  • Vue的依赖收集

    原文地址//依赖收集器

  • 变化侦测篇

    概念 vue的最大特点之一就是数据驱动视图, 我们可以把数据理解为状态, 而视图就是用户可直观看到页面, 页面不...

  • Object变化侦测

    什么是变化侦测 运行时,内部状态可能会发生变化,相应页面要重新渲染,变化侦测就是弄清楚是哪里发生了变化。从实现的方...

  • 深入浅出 - vue变化侦测原理

    原文链接如果感兴趣可以加我微信: xiaobei060537, 一起交流。 深入浅出 - vue变化侦测原理 其实...

网友评论

      本文标题:vue知识点-1--变化侦测-依赖收集

      本文链接:https://www.haomeiwen.com/subject/juhtoctx.html