美文网首页
vue源码阅读-究极简化版的依赖收集源码

vue源码阅读-究极简化版的依赖收集源码

作者: 景阳冈大虫在此 | 来源:发表于2020-10-15 11:22 被阅读0次
响应式原理

vue是一个MVVM框架。
通俗理解,就是通过响应式对象,可以实现页面内容发生变动之后触发数据Model变化,Model发生变化可以触发页面重新渲染。
关于原理有好多文章也讲得很清楚,这里做一下源码的大删除,只保留关键部分易于理解。

简单来说

  1. 响应式对象会拥有__ob__属性,用以保存用他自己为入参创建的Observer实例。
  2. data的每一个属性都拥有自己的Dep实例:dep;
  3. Dep.target:target是Dep.prototype的属性。这也就意味着每一个Dep实例共用一个Dep.target。同一时间只会有一个watcher实例。
  4. 读取data[key],会触发这个key的get,此时会判断存在Dep.target的Watcher实例。调用dep.depend,将当前的Watcher塞进dep.subs里。subs会存储所有需要这个值的watcher。
  5. 修改data[key],会调用dep.notify,即触发每个watcher.update,其实就是watcher.get。
  6. watcher.get:
    1> getter: updateComponent = () => { vm._update(vm._render(), hydrating) }
    2> render:生成渲染树,完成对当前vue实例vm的数据访问,触发Observer对data属性做的getter
    3> update里面会调用patch :把 VNode 转换成真正的 DOM 节点。页面将会重新渲染。

Observer

Observer会处理data,使其变成响应式对象。
比较直观地感受,如果我们在编写组件时,template里面要用到的数据没有在data里声明,会出现一个报错,Vue 将警告你渲染函数正在试图访问不存在的 property。

class Observer{
    constructor(data){
        def(value, '__ob__', this) 
        this.walk(data);
    }
    walk(obj){
        const keys=Object.keys(obj);
        for(let i=0;i<keys.length;i++){
            defineReactive(obj,keys[i])
        }
    }
}
function defineReactive(obj,key){
    let val=obj[key];
    const dep=new Dep();
    Object.defineProperty(obj,key,{
        enumerable:true,
        configurable:true,
        get(){
            Dep.target&&dep.depend(); // dep.subs.push(Dep.target)
            return val;
        }
        set(newVal){
            if(val==newVal) return ;
            val=newVal;
            dep.notify();
        }
    })
}

Dep

class Dep{
    subs:[],
    id;
    target,
    depend(){
        Dep.target.addDep(this);
    }
    notify(){
        for(let i in this.subs){
            subs[i].update();
        }
    }
    addSub(watcher){
        this.subs.push(watcher);
    }
    removeSub (sub: Watcher) {
        remove(this.subs, sub) // Array.splice
    }
}

Watcher

class Watcher{
    newDeps:[],
    constructor(){
        this.get();
    }
    addDep(dep){
       this.newDepIds.add(id)
        this.newDeps.push(dep)
        dep.addSub(this);
    }
    update(){
        this.run();
    }
    run(){
        this.get();
    }
    get(){
        pushTarget(this); // Dep.target=this;
        // getter: updateComponent = () => { vm._update(vm._render(), hydrating) }
         // render:生成渲染树,完成对当前vue实例vm的数据访问,触发Observer对data属性做的getter
         //update: patch :把 VNode 转换成真正的 DOM 节点
        this.getter.call(vm,vm);
        popTarget();
    }
    teardown(){
         if (this.active) {
      // remove self from vm's watcher list
      // this is a somewhat expensive operation so we skip it
      // if the vm is being destroyed.
      if (!this.vm._isBeingDestroyed) {
        remove(this.vm._watchers, this)
      }
      let i = this.deps.length
      while (i--) {
        this.deps[i].removeSub(this)
      }
      this.active = false
    }
    }
}
移除监听
  1. 每一个Watcher实例会拥有一个数组[Dep],在getter里使用Dep.depend收集依赖时,调用的Watcher.addDep,不仅会对Observerdep.subs.push(Watcher),也会对当前Watcher.deps.push(dep)。这个Watcher.deps就是收集的依赖。
  2. 如果希望解除data[某属性]watcher的依赖关系,则会调用Watcher.teardown,此时将会对Watcher拥有的deps的每一个dep实例调用removeSub,其实就是使用Array.splice删去当前的Watcher

本文参考:https://juejin.im/post/6844903634891735054

相关文章

  • vue源码阅读-究极简化版的依赖收集源码

    vue是一个MVVM框架。通俗理解,就是通过响应式对象,可以实现页面内容发生变动之后触发数据Model变化,Mod...

  • vue源码调试

    1.下载vue源码的2.6.12版本的vue源码 2.源码下载好了以后,下载依赖 npm install3.依赖安...

  • 04Vue源码剖析01

    Vue源码剖析01 Vue 源码地址 文件结构 源码目录 调试 环境搭建 安装依赖:npm i 安装 rollup...

  • 2020 一起读 vue 源码

    最近在收集一些资料来帮助自己理解和阅读 vue 的源码。在学习和阅读过程中,发现我们读解 vue 源码难度是在于很...

  • Vue源码原理--依赖收集

    为何要进行依赖收集 先看下面这段代码 按照之前的文章响应式原理中的方法绑定则会出现一个问题---text3在实际模...

  • vue源码解读--依赖收集

    经过上一节(响应式的创建过程[https://www.jianshu.com/p/aa6a6c3eaeb2])分析...

  • 简单版源码分析双向绑定

    从源码分析双向绑定 这部分代码,是源码的简化版,相对比较容易理解。 html代码: 从html代码,vue仅仅从初...

  • Vue源码实现--依赖收集(1)

    最近闲来在比较深入的学习vue的源码,受益匪浅,在这边记录一些心得,顺便给自己定个小目标--自己实现一个简单的vu...

  • Vue源码实现--依赖收集(2)

    关于上一篇的几点疑问其实在看源码的过程中已经看明白了,但是回过头来发现又容易忘了,这也是我决定写几篇文章记录一下的...

  • Vue源码实现--依赖收集(3)

    watch一个Computed属性:  其实了解完前面的依赖收集原理之后,watch一个computed属性和da...

网友评论

      本文标题:vue源码阅读-究极简化版的依赖收集源码

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