写文章不容易,点个赞呗兄弟 专一 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工做原理,源码版助于了解内部详情,让咱们一块儿学习吧 研究基于 Vue版本 【2.5.17】闭包
若是你以为排版难看,请点击 下面连接 或者 拉到 下面关注公众号也能够吧函数
若是对依赖收集彻底没有概念的同窗,能够先看我这篇白话版this
响应式原理 - 白话版 prototype
咱们已经讲过了 依赖收集code
【Vue原理】依赖收集 - 源码版之引用数据类型 token
如今就要看依赖更新了哈哈哈,毕竟收集完是要更新的嘛get
其实依赖更新挺简单的,就是两步源码
修改属性值 通知保存的依赖进行更新 重点只须要看 Object.defineProperty 设置的set 函数,当给数据重赋新值的时候,天然会触发 set 函数,完成依赖更新
function defineReactive(obj, key, val) { var dep = new Dep(); var childOb = observe(val); Object.defineProperty(obj, key, { get(){ ... 属性被读取,完成依赖收集 // 返回闭包值 return val }, set(newVal) { // 值没有变化 if (newVal ===val) return // 修改闭包值 val = newVal; // 若是属性已经存在过,设置新值的时候,会从新调用一遍 childOb = observe(newVal); // 触发更新 dep.notify(); } }); }
依赖更新重点就重在 通知更新
而通知更新的重点,只有一句话,【dep.notify】
因此,咱们重点去了解这句话,如何通知,如何更新
好的, dep 在第一篇讲过了
咱们知道,dep 主要是存储依赖的,再看一遍源码
var Dep = function Dep() { this.subs = []; // 依赖存储器 }; // 遍历 subs ,逐个通知依赖,就是逐个调用 watcher.update Dep.prototype.notify = function() { var subs = this.subs.slice(); for (var i = 0, l = subs.length; i < l; i++) { subs[i].update(); } };
看过了源码,咱们知道了,原来通知更新是【遍历依赖存储器】,而后一个个【调用 watcher.update】
由于 subs 装的是 watcher,因此,subs[0].update 就是 watcher.update
因而问题又来了,watcher.update 是怎么就更新了???
function Watcher(vm, expOrFn) { this.vm = vm; // 保存传入的更新函数 this.getter = expOrFn; // 新建 watcher 的时候,当即执行更新函数 this.get(); }; Watcher.prototype.get = function() { // 执行更新函数 this.getter.call(this.vm,this.vm); }; Watcher.prototype.update = function() { this.get() }
看到上面的源码
1Watcher 新建实例的时候,会保存传入的函数(这个函数会做为更新用)
2watcher 实例有 update 方法,做用是执行上一步保存的更新函数
那么 watcher 是何时开始建立的呢?
以页面 watcher 举例,探索整个实例构建的基本流程
function Vue(options) { this._init(options); } Vue.prototype._init = function(options) { // ...处理组件选项等 this.$mount() } Vue.prototype.$mount = function() { // ...解析template成redner函数保存 /** 每一个实例新建一个watcher, 而且利用watcher 保存更新函数 **/ new Watcher(this, // 这个函数是更新函数,传入watcher保存下来,用于后面页面初始化或者页面更新 function() { /** ...调用保存的渲染函数生成VNode, 并生成DOM插入页面中**/ } ); };
看上面的源码 和注释大概就能够很清楚了
从 【new Vue】 到 【vm._init】 初始化 到 【vm.$mount】 挂载到页面,整个流程就完整了
重点是清楚 watcher的更新函数
更新函数
咱们能够看到这个页面的更新函数,做用是调用 渲染函数,而后生成DOM节点插入页面中。
更新函数会传入Watcher ,而后被保存到 watcher 的实例中
“整个函数涉及的源码不少,可是这里一概而过”
因此,通知更新作了这些工做
一、直接调用 watcher.update,也就是从新调用给 watcher 保存的更新函数
二、更新更新函数就是执行渲染函数,而后读取实例最新的值(已被修改过的值),最后从新生成DOM 节点
三、DOM 节点 插入或替换页面,完成更新
画个通知流程图