当我精通vue2的源码dep和watcher的关系时

Vue源码分析之数据绑定Dep与Watcher的关系 数据绑定 数据绑定 一旦更新了data中的某个属性数据,所有界面上直接(this.xxx='aaa')或间接(计算属性或方法)使用了此属性的节点都会更新 数据劫持 数据劫持是vue中用来实现数据绑定的一种技术 基本思想:通过defineProperty()来监视data中所有属性(任意层次)数据的变化,一旦变更就去更新界面 ... 阅读详情

在这里插入图片描述

watcher与dep的关系程序运行分析

初始化执行 _init => initState() + vm.$mounted

initState => initData + initWatch + initComputed

  1. initData 中执行observer(),进行响应式处理
  • 创建Observer类 => Observer类中对data进行遍历defineReactive,修改get和set函数
  • defineReactive函数中创建私有变量dep(new Dep),每一个get和set对应一个dep
  • get中判断Dep类的静态属性target有值,当前watcher的deps添加当前dep,当前dep的subs添加当前watcher;并返回value;
  • set中赋值后执行dep.notify函数,执行dep的subs中的watcher循环update(执行queueWatcher=>flushWatcher=>延迟队列queue中watcher.run=>执行再次更新);
  1. initWatch
  • 截取watch的key属性和监听需要处理的handler函数
  • 对每一个key创建一个watcher,watcher函数中如果有user则获取到值后再次执行handler函数,实现监听功能
//            vm key handler
new Watcher(vm,exprOrfn,handler,{...options,user:true}
  1. initComputed
  • 获取到所有computed属性的key,handler
  • 创建vm._computedWatcher,遍历赋值key:new Watcher
for(let key in computed){
    // getters 为computed的handler计算函数
    // lazy:true在watcher中区分时computed的属性,执行函数为计算函数
    // watcher中用dirty取初始化lazy,默认为true,表示第一次或者需要再次执行handler计算函数,为false读取缓存的值,即watcher的value
    _computedWatcher[key] = 
    new Watcher(vm,getters||handler,()=>{},{lazy:true})
  • 遍历computed,进行defineComputed,对每一个key进行劫持修改get函数
  • get的值为_computedWatcher对应key的watcher.value
  • 如果dirty为true(默认值,或修改值后赋为true),执行watcher.evaluate方法即computed的handler方法,执行完dirty = false
  • 判断如果Dep.target有,收集渲染watcher

vm.$mounted 挂载dom

  1. 拿到vm.el的outerHTML
  2. 转换为ast语法树
  3. 转为render函数(_s 解析变量 _v解析文本,_c解析标签),通过with函数实现解析_s函数this.变量的值。
  4. 执行mountedComponent函数
  5. 执行各个运行的钩子函数(beforeMounted,updated,mounted)
  6. 创建watcher实例 (lifecyle.js)
    // _render拿到的是虚拟dom解构数据
    let updateComponent = ()=>{
        vm._update(vm._render())
    }
    new watcher(vm,updateComponent,()=>{
        callHook(vm,'updated') //订阅
    },true)
  1. watcher中执行get方法
    pushTarget(this) 
    const value = this.getters.call(this.vm,this)
    popTarget() 

  1. pushTarget:先给Dep添加当前watcher至target
  2. 执行getters即_update方法:通过with函数实现解析_s函数this.变量的值,此时会调用该变量的obsercer中定义的get方法,Dep.target有值,执行dep.depend(),进行watcher dep互相收集,最后移除Dep的target
//  watcher为当前渲染watcher,dep为每一个definReactive中的私有变量 dep = new Dep()
    dep.depend() =>  Dep.target.addDep(this)  =>  watcher.addDep(dep) =>
    watcher.addDep(dep)=>{
        // 在watcher中deps添加dep
        this.deps.push(dep)
        this.depsId.add(id)
        //dep中subs也添加当前watcher
        dep.addSub(this(watcher)) 
    }
  1. 运行patch函数,通过diff算法实现最小量更新渲染真实DOM

总结

new watcher的地方有三处

  1. lifecycle中:mountComponent方法挂载dom。此watcher为一个渲染watcher,自动执行的get函数为渲染dom函数,回调函数为upadted钩子函数
    new watcher(vm,updateComponent,()=>{callHook(vm,'updated') },true)
  1. initState中,initWatch方法,对每一个key创建一个watcher,watcher函数中如果有user则获取到值后再次执行handler函数,实现监听功能
//            vm key handler
new Watcher(vm,exprOrfn,handler,{...options,user:true}

new watcher 默认执行get函数,读取一次vm.data的值,调用observe的get,进行依赖收集,defineReactive函数中的私有变量dep再次收集watch监听的watcher。set该变量时,dep.notify会挨个通知执行subs中的watcher

  1. initState中,**执行initComputed方法,此watcher是一个计算watcher,get函数为computed配置项里的计算函数。**无回调函数,options参数lazy=true,在watcher中区分是computed的watcher,初始化watcher不执行get函数。读取computed属性时,触发defineProperty劫持的getter方法,最终取值为watcher.value。其中如果第一次取值dirty为ture,计算watcher.evaluate,缓存value。以后取值读取缓存value,dirty赋为false,除非调用该watcher的update方法,dirty为true,再次调用才会重新计算evaluate
 new Watcher(vm,getters||handler,()=>{},{lazy:true})

Q:computed的get方法中:判断if(Dep.target)再进行watcher.depend()互相收集依赖,Dep.target不是每次赋值完就pop吗?Dep中,stack什么情况下length>1?

A:当计算computed的值时,取到vm的变量,触发observe中的getter,此时Dep.target为computed的watcher,再observe中
会将各个变量 fisrtName lastName的dep中push computed-watcher,再computed-watcher的deps中push firstName和
lastName的dep.

new Dep

在给每个data进行响应式处理时,defineReactive函数里定义私有变量,dep=Dep(),没一个变量都可以找到一个对应的dep

Q: 一个变量对应一个dep,对应一个渲染watcher,可以有多个computed watcher,一个watch watcher, 对不对?
A:一个变量对应一个dep:data中每一个变量进行数据劫持(定义getter)时,定义一个私有变量dep,只能通过变量getter时获取得到
watcher有以下几种

  1. 渲染watcher 即render watcher, 在初始化数据劫持后执行后执行,初始执行函数为vm._update 渲染dom
  2. computed watcher,1 执行完毕后执行初始化绑定opiton里的wathcer配置项,主执行函数为计算函数,计算时会取vm的变量,调用observe的getter,此时Dep.target有值,会进行子变量的dep和当前计算watcher的互相收集
  3. watch watcher,1 执行完毕后初始化,拿到options watch配置的key和handler,初始化watcher,此时主函数是个字符串key,初始执行为自定义watcher的getter计算watcher.value来获取oldValue,该过程中调用vm.变量,同样进行2中的互相收集,该watcher的cb函数为配置项的handler:即监听后的用户处理回调;最后一个配置项user:true,用来区分update时,获取到新值后再执行回调函数。

附上本人github的学习仓库 learn-vue2-source-code (有大量注释)
p:求求给点个star吧😍

八小时实现迷你版vuejs五:实现Watcher 再贴一下之前的一张图: 我们已经实现了 Observer 和 Directive,并且自己实现了一个 v-on 的指令,那么再实现 Dep 和 Watcher 就完整了。这里的 dep.js 其实就是一个记录依赖关系的,他有一个内部的数组 subs 会把所有依赖的 watcher 记录在里面,然后 observer 在观察到数据改变的时候,就告诉dep,它会负责遍历 subs 并调用他们的 upd 阅读详情

相关推荐

vue.js源码解读系列 - 剖析observer,dep,watch三者关系 如何具体的实现数据双向绑定

Vue双向数据绑定的核心和基础api是Object.defineProperty,其内部真正参与数据双向绑定流程的主要有Obderver、Dep和Watcher,基于defineProperty和发布者订阅者模式,最终实现数据的双向绑定。那么Obderver、Dep和Watcher是如何具体配合工作的呢?下面就来理一理。

wangweianger的博客 4951

说说Vue响应式系统中的Watcher和Dep的关系-面试进阶

响应系统中的Watcher即这个系统的观察者,它是响应系统中观察者模式的载体,当响应系统中的数据发生改变的时候,它能够知道并且执行相应的函数以达到某种业务逻辑的目的。打个比方,如果你是一个商家,要寄一批货分别给不同的客户,那么watcher就是一个个快递员,发出的动作就是数据发生改变。你只需要负责寄出去这个动作就行了,如何找到、送到客户则是watcher的事情。每个watcher和数据之间的关系要么是1对1,要么是多对多关系(这与watcher的类型有关),要不是没有联系。watcher。

bb_xiaxia1998的博客 271

Vue另类解读--基于数据劫持的双向绑定Observer/Watcher/Dep

Vue另类解读--基于数据劫持的双向绑定直接解读类比Observer(教官)Dep(小本子)Watcher(作战指挥官) 基于数据劫持的双向绑定,想必很多人都能理解清楚,这里就不多做描述了。只是在读Vue的基于数据劫持的双向绑定相关源码时感觉特别绕。这里记录下我对 Observer,Watcher,Dep这三者作用与关系之间的思考。 以下我是站在源码的角度进行分析的,希望能帮读源码的朋友理清思路。 直接解读 首先摊开所有的关键点: 这里的watcher与this.watch没有关系,反倒是this.com

Lawliet_Hero的博客 674

Vue 中 Dep 和 Observer 的用法详解

Vue 中响应式系统利用了订阅发布模式来实现基本的逻辑。本文将介绍其中的两个重要角色,他们就是Dep和Observer。其中Observer 是观察者和 Dep是订阅收集和发布者。另外watcher是作为订阅者的角色。本文将重点将Observer和Dep。 一:Observer vue 通过Observer 构造函数,为响应式变量添加访问和赋值的get set的回调。 var Observer...

陆小森_红齐飘飘的博客 9487

Vue2 源码解析:2. Dep 与 Watcher 核心类

Dep:作为依赖收集容器,每个响应式数据属性对应一个Dep实例,负责管理依赖它的WatcherWatcher:作为依赖的具体表现,连接数据和更新逻辑,接收数据变化通知并执行相应操作它们的协作实现了Vue的核心特性——响应式,使得开发者可以专注于数据逻辑,而无需手动操作DOM。理解这两个类的实现,有助于深入掌握Vue的工作原理和性能优化方向。

weixin_63215361的博客 777

基于74LS175的四人抢答电路设计(含详细设计分析及试错过程)

根据设计要求不难发现,只要有一人抢答,就会输出信号使指示灯常亮,此时其他人输入无效,适宜选择触发器,有人抢答时触发器输出由0变1,输出信号控制指示灯常亮,同时使CLR引脚输入0,触发器不工作,即其他选手不能再抢答。尝试加入一人抢答后其他人不可抢答功能,如下图,175四个~Q输出端接入同一个与非门,于是当有选手抢答时该与非门输出由0变1,将该信号输入U5A,U5A输出由1变0,接入~CLR即可使电路不再工作。但仿真时发现,该复位键仅可使抢答电路部分复位,计数部分只是暂停,并未复位。否则元器件将无法正常工作。

2202_75463653的博客 8188

Vue的响应式原理-两个创建Dep的位置

在`Vue`响应式的`class Observer`部分,我们发现会有两个部分都创建了`Dep`实例。分别为1:defineReactive创建的dep 2:Observer创建的dep,那么这两个dep到底都是干什么用的呢?

block_xu的博客 734

别再乱改grub.cfg了!手把手教你用GRUB2自定义多系统启动菜单(含UEFI/BIOS双模式配置)

本文详细介绍了如何安全、高效地使用GRUB2自定义多系统启动菜单,涵盖UEFI/BIOS双模式配置。通过避免直接编辑grub.cfg文件,采用正确的配置方法和命令,帮助用户打造稳定且美观的启动环境,特别适合Linux多系统用户和开发者。

weixin_42553471的博客 590

Vue源码解读之Dep,Observer和Watcher

在解读Dep,Observer和Watcher之前,首先我去了解了一下Vue的数据双向绑定,即MVVM,学习于:https://blog.csdn.net/u013321...以及关于Observer和watcher的学习来自于:https://www.jb51.net/article/... 整体过程 Vue实例化一个对象的具体过程如下: 新创建一个实例后,Vue调用compile将el转换成...

w1366352655的博客 2742

别再只用串口助手了!用LabVIEW给STM32F103C8T6做个专属上位机(附完整源码)

本文详细介绍了如何利用LabVIEW为STM32F103C8T6开发定制化上位机,替代传统串口助手,实现高效数据交互。内容涵盖硬件架构设计、STM32固件优化、LabVIEW上位机开发技巧及工业级应用案例,特别适合需要实时数据采集与处理的工控场景。

weixin_42524762的博客 367

高速DAC时钟与配置实战:DAC5681Z硬件设计与寄存器编程详解

在高速数据转换系统中,时钟信号是决定系统性能的核心要素,其稳定性和纯净度直接影响数模转换器(DAC)的输出频谱纯度与动态范围。时钟电路的设计原理涉及信号完整性、阻抗匹配与直流偏置,而内部锁相环(PLL)和延迟锁相环(DLL)的配置则是实现精确时序控制的关键技术。这些技术的价值在于,它们共同保障了高速通信、雷达和任意波形生成等应用对信号实时性与精度的严苛要求。本文聚焦于德州仪器(TI)的DAC5681Z,深入解析其外部时钟输入电路的硬件设计要点,包括端接电阻的计算与选型,并详细拆解通过串行外设接口(SPI)对

weixin_30342363的博客 186

Vue源码解析系列——响应式原理篇:理解Dep类和Watcher类

写在前面 这一篇我们先不着急阅读源码,因为接下来需要用到一个比较复杂的设计模式:观察者模式,而且还需要理解依赖收集才能继续向下阅读源码,所以这次我们先做一个铺垫。 依赖收集 通过之前阅读的源码我们了解到Vue2.x版本的响应式是依靠Object.defineProperty这个API来进行对象的劫持,当对象进行取值和赋值操作的时候,都可以进行一些另外的操作。在get过程中,也就是对象的取值,Vue做的操作是:依赖收集。 那么什么是依赖? 这里我们举一个例子: <template> <di

hd101367816的博客 2289

5G核心网Framed Routing功能解析:基于PFCP的帧路由机制与多终端互联实践

5G核心网Framed Routing功能解析:基于PFCP的帧路由机制与多终端互联实践

大家好,我是码农老gou,一名专注于编程技术的程序员。在这个博客中,我将与大家分享我在工作和学习中的经验、见解以及一些实用的技术干货。 1463

Vue源码分析:Watcher收集Dep原因

Vue响应式系统中Watcher与Dep的双向依赖机制是核心实现。Watcher通过get()方法触发依赖收集时,会将自身压入Dep.target栈,在属性访问时Dep会收集当前Watcher。同时,Watcher也会记录所有依赖的Dep实例(存储在deps和newDeps中),这种双向记录的关键作用在于:1)实现依赖清理(cleanupDeps),移除不再需要的依赖关系;2)避免重复收集依赖(通过depIds去重)。这种设计确保了响应式系统能精确追踪依赖关系,在属性变化时高效通知相关Watcher更新。

油墨香^-^的博客 997

flowable工作流看这一篇就够了(基础篇)

接下来我们构建一个非常简单的请假流程,Flowable引擎需要流程定义为BPMN 2.0格式,这是一个业界广泛接受的XML标准。在Flowable术语中,我们将其称为一个流程定义(process definition)。一个流程定义可以启动多个流程实例(process instance)。流程定义可以看做是重复执行流程的蓝图。在这个例子中,流程定义定义了请假的各个步骤,而一个流程实例对应某个雇员提出的一个请假申请。

qq_38196449的博客 2万+

【报错】ImportError: libpython3.10.so.1.0: cannot open shared object file: No such file or directory

ImportError: libpython3.10.so.1.0: cannot open shared object file: No such file or directory

静谧、淡雅 859

[vue2源码]深度理解Vue中Observer,Dep,Watcher以及解决监听Array数组变化

双向绑定 首先通过一次渲染操作触发Data的getter进行依赖收集 在data发生变化的时候会触发它的setter setter通知Watcher Watcher进行回调通知组件重新渲染的函数 diff算法来决定是否发生视图的更新 Observe 每个数据都有一个标记,防止重复绑定 Observer为数据加上响应式属性进行双向绑定,如果是对象,则进行深度遍历,为每一个子对象都绑定上方法,如果是数组,对每个成员进行遍历绑定方法 源码解析: export class Observer { valu

一再问究竟的博客 2179

ComfyUI整合包V8中文版最新版介绍

和普通AI绘图网页不同,它把图像生成的每一个步骤拆分成一个个"节点",用连线把它们串起来,形成工作流。里面包含ComfyUI内核、Python运行环境、常用插件、部分预置模型,还有一个叫"绘世启动器"的图形界面管理工具。网上的对比数据显示,WebUI最低需要4G显存,ComfyUI最低3G显存就能运行。可以在里面管理插件、切换模型路径、设置显存模式、查看日志报错,还有"疑难解答"功能,遇到报错可以先扫描一下看是不是已知问题。原版ComfyUI的界面是英文的,右键菜单、节点名称全是英文。

欢迎来到鸾姝淡月博客,专为程序员和编程爱好者打造的技术博客。我们分享编程语言趋势、开发工具、编程哲学、职业发展等,助你掌握新技术,优化技能,激发编程热情。 5225

Vue 源码学习过程 - Observer/Dep/Watcher三者实现数据双向绑定

Vue版本: vue@2.5.10,简单记录自己的学习过程 目录 实现双向绑定的方式区别 Vue实现数据劫持的方式 了解defineProperty Observer/Dep/Watcher三者实现 1. Observer 2. Dep 3.Watcher 实现双向绑定的方式区别 脏值检测(angularjs) 这种模式下,使用之只有触发指定的事件进入脏值检测,才会进行双向...

u011374329的博客 1773

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

【手写 Vue2.x 源码】第二十二篇 - dep 和 watcher 关联

本篇, dep 和 watcher 关联;1,介绍了依赖收集的必要性;2,介绍了 Watcher 和 Dep 的作用;3,实现了 Watcher 类和 Dep 类;4,Watcher 和 Dep 如何产生关联;

BraveWangDev 1369

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

【Vue源码】数据响应式原理 - 依赖收集 - defineReactive - Observer - Dep - Watcher

我们在使用Vue时,只需要修改数据,视图就会自动更新,这就是数据响应 今天来学习Vue实现数据响应式的原理~

YK菌的博客 5684

Vue 2.6.13 源码解析(四) Observer、Dep、Watcher与订阅

Vue 2.6.13 源码解析(四) Observer、Dep、Watcher与订阅

白瑕 的博客 1936

vue2 源码解析-双向数据绑定原理

1、vue 2 是通过Object.defineProperty()对组件内的data数据进行递归绑定getter和setter,同时通过Dep进行依赖收集管理2、vue2 是(通过Object.defineProperty递归遍历)劫持的属性3、vue3 是(通过proxy代理)劫持的整个data对象。

weixin_44862629的博客 1824

通俗易懂的 Vue - Computed 原理(Watcher and Dep)

大家好,新人一个,初次写博客还请大家多多关照。 对于Vue的响应式,想必大家都有所了解,在Vue响应式数据中,computed是比较特殊的响应式数据,它们可以监听使用到的数据,数据 改变computed的数据也会重新计算。 今天主要是讨论 computed 实现原理 。 computed在内部主要是运用 Watcher和 Dep构造函数进行收集依赖和派发更新。 咱们先来看看 Watcher和 Dep源码。 var uid = 0; /** * dep 就是用来给每...

十七的博客 2155
上一篇: webpack初级进化
下一篇: 前端模块化 CommonJs、AMD、CMD、UMD、ESmodule 发展历程与关系
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值