210、VUE之Dep,Observer和Watcher

来源:https://www.cnblogs.com/datiangou/p/10144883.html

dep是可以有多个指令订阅的可观察对象。
new Watcher在mountComponent、initComputed、stateMixin里执行。 new Dep在Observer、defineReactive$$1里执行。new Observer在observe里执行。observe在全局、observeArray、defineReactive$$1、validateProp、initState、initData、observable(initGlobalAPI)里执行。defineReactive$$1在walk、set、initInjections、initRender、initProps里执行。 Vue实例化一个对象的具体过程如下: 1、新创建一个实例后,Vue调用compile将el转换成vnode。 2、调用initState, 创建props, data对象的钩子以及其对象成员的Observer(添加getter和setter)。 3、执行mount挂载操作,在挂载时建立一个直接对应render的Watcher,并且编译模板生成render函数,执行vm._update来更新DOM。 4、每当有数据改变,都将通知相应的Watcher执行回调函数,更新视图。 (1)当给这个对象的某个属性赋值时,就会触发set方法。 (2)set函数调用,触发Dep的notify()向对应的Watcher通知变化。 (3)Watcher调用update方法。 在这4个过程中: 1、Observer是用来给数据添加Dep依赖。 2、Dep是data每个对象包括子对象都拥有一个该对象, 当所绑定的数据有变更时, 通过dep.notify()通知Watcher。 3、Compile是HTML指令解析器,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数。 4、Watcher是连接Observer和Compile的桥梁,Compile解析指令时会创建一个对应的Watcher并绑定update方法 , 添加到Dep对象上。 在这里插入图片描述 接下来我们来分析一下对象具体的代码实现。 Observer var Observer = function Observer (value) { this.value = value; this.dep = new Dep(); this.vmCount = 0; // 给value添加__ob__属性,值就是本Observer对象,value.__ob__ = this; // Vue.$data 中每个对象都 __ob__ 属性,包括 Vue.$data对象本身 def(value, '__ob__', this); //判断是否为数组,不是的话调用walk()添加getter和setter //如果是数组,调用observeArray()遍历数组,为数组内每个对象添加getter和setter if (Array.isArray(value)) { var augment = hasProto ? protoAugment : copyAugment; augment(value, arrayMethods, arrayKeys); this.observeArray(value); } else { this.walk(value); } }; walk和defineReactive // 遍历每个属性并将它们转换为getter/setter。只有当值类型为对象时才调用此方法。 Observer.prototype.walk = function walk (obj) { var keys = Object.keys(obj); for (var i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]); } }; function defineReactive ( obj, key, val, customSetter, shallow ) { var dep = new Dep(); var property = Object.getOwnPropertyDescriptor(obj, key); if (property && property.configurable === false) { return } //获取已经实现的 getter /setter 方法 var getter = property && property.get; var setter = property && property.set; if ((!getter || setter) && arguments.length === 2) { val = obj[key]; } var childOb = !shallow && observe(val); Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { var value = getter ? getter.call(obj) : val; //Dep.target 全局变量指向的就是当前正在解析指令的Complie生成的 Watcher // 会执行到 dep.addSub(Dep.target), 将 Watcher 添加到 Dep 对象的 Watcher 列表中 if (Dep.target) { dep.depend(); if (childOb) { childOb.dep.depend(); if (Array.isArray(value)) { dependArray(value); } } } return value }, set: function reactiveSetter (newVal) { var value = getter ? getter.call(obj) : val; /* eslint-disable no-self-compare */ if (newVal === value || (newVal !== newVal && value !== value)) { return } /* eslint-enable no-self-compare */ if ("development" !== 'production' && customSetter) { customSetter(); } if (setter) { setter.call(obj, newVal); } else { val = newVal; } childOb = !shallow && observe(newVal); dep.notify();//如果数据被重新赋值了, 调用 Dep 的 notify 方法, 通知所有的 Watcher } }); } observeArray和observe Observer.prototype.observeArray = function observeArray (items) { for (var i = 0, l = items.length; i < l; i++) { // 如果是数组继续执行 observe 方法, 其中会继续新建 Observer 对象, 直到穷举完毕执行 walk 方法 observe(items[i]); } }; function observe (value, asRootData) { if (!isObject(value) || value instanceof VNode) { return } var ob; if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { ob = value.__ob__; } else if ( shouldObserve && !isServerRendering() && (Array.isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue ) { ob = new Observer(value); } if (asRootData && ob) { ob.vmCount++; } return ob } Dep // Dep是订阅者Watcher对应的数据依赖 var Dep = function Dep () { //每个Dep都有唯一的ID this.id = uid++; //subs用于存放依赖 this.subs = []; }; //向subs数组添加依赖 Dep.prototype.addSub = function addSub (sub) { this.subs.push(sub); }; //移除依赖 Dep.prototype.removeSub = function removeSub (sub) { remove(this.subs, sub); }; //设置某个Watcher的依赖 //这里添加了Dep.target是否存在的判断,目的是判断是不是Watcher的构造函数调用 //也就是说判断他是Watcher的this.get调用的,而不是普通调用 Dep.prototype.depend = function depend () { if (Dep.target) { Dep.target.addDep(this); } }; Dep.prototype.notify = function notify () { var subs = this.subs.slice(); //通知所有绑定 Watcher。调用watcher的update() for (var i = 0, l = subs.length; i < l; i++) { subs[i].update(); } }; Watcher 在initMixin()初始化完成Vue实例所有的配置之后,在最后根据el是否存在,调用$mount()实现挂载。 if (vm.$options.el) { vm.$mount(vm.$options.el); } $mount //这是供外部使用的公共的方法 Vue.prototype.$mount = function ( el, hydrating ) { el = el && inBrowser ? query(el) : undefined; return mountComponent(this, el, hydrating) }; mountComponent function mountComponent ( vm, el, hydrating ) { vm.$el = el; //这个if判断目的在检测vm.$options.render if (!vm.$options.render) { vm.$options.render = createEmptyVNode; { if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') || vm.$options.el || el) { warn( 'You are using the runtime-only build of Vue where the template ' + 'compiler is not available. Either pre-compile the templates into ' + 'render functions, or use the compiler-included build.', vm ); } else { warn( 'Failed to mount component: template or render function not defined.', vm ); } } } // 调用钩子函数 callHook(vm, 'beforeMount'); // 定义updateComponent,将作为Watcher对象的参数传入。 var updateComponent; /* istanbul ignore if */ if ("development" !== 'production' && config.performance && mark) { updateComponent = function () { var name = vm._name; var id = vm._uid; var startTag = "vue-perf-start:" + id; var endTag = "vue-perf-end:" + id; mark(startTag); var vnode = vm._render(); mark(endTag); measure(("vue " + name + " render"), startTag, endTag); mark(startTag); vm._update(vnode, hydrating); mark(endTag); measure(("vue " + name + " patch"), startTag, endTag); }; } else { updateComponent = function () { vm._update(vm._render(), hydrating); }; } new Watcher(vm, updateComponent, noop, { before: function before () { if (vm._isMounted) { callHook(vm, 'beforeUpdate'); } } }, true /* isRenderWatcher */); hydrating = false; // 调用钩子 if (vm.$vnode == null) { vm._isMounted = true; callHook(vm, 'mounted'); } return vm } watcher mountComponent在构造新的Watcher对象传了当前vue实例、updateComponent函数、空函数这三个参数。 var Watcher = function Watcher ( vm, expOrFn, cb, options, isRenderWatcher ) { this.vm = vm; if (isRenderWatcher) { vm._watcher = this; } // 当前Watcher添加到vue实例上 vm._watchers.push(this); // 参数配置,options默认false if (options) { this.deep = !!options.deep; this.user = !!options.user; this.computed = !!options.computed; this.sync = !!options.sync; this.before = options.before; } else { this.deep = this.user = this.computed = this.sync = false; } this.cb = cb; this.id = ++uid$1; // uid for batching this.active = true; this.dirty = this.computed; //用于计算属性 this.deps = []; this.newDeps = []; //内容不可重复的数组对象 this.depIds = new _Set(); this.newDepIds = new _Set(); this.expression = expOrFn.toString(); //将watcher对象的getter设为updateComponent方法 if (typeof expOrFn === 'function') { this.getter = expOrFn; } else { this.getter = parsePath(expOrFn); if (!this.getter) { this.getter = function () {}; "development" !== 'production' && warn( "Failed watching path: \"" + expOrFn + "\" " + 'Watcher only accepts simple dot-delimited paths. ' + 'For full control, use a function instead.', vm ); } } //如果是计算属性,就创建Dep数据依赖,否则通过get获取value if (this.computed) { this.value = undefined; this.dep = new Dep(); } else { this.value = this.get(); } }; }; get Watcher.prototype.get = function get () { pushTarget(this);//将Dep的target添加到targetStack,同时Dep的target赋值为当前watcher对象 var value; var vm = this.vm; try { // 调用updateComponent方法 value = this.getter.call(vm, vm); } catch (e) { if (this.user) { handleError(e, vm, ("getter for watcher \"" + (this.expression) + "\"")); } else { throw e } } finally { // "touch" every property so they are all tracked as // dependencies for deep watching if (this.deep) { traverse(value); } popTarget();//update执行完成后,又将Dep.target从targetStack弹出。 this.cleanupDeps(); } return value }; //这是全局唯一的,因为任何时候都可能只有一个watcher正在评估。 Dep.target = null; var targetStack = []; function pushTarget (_target) { if (Dep.target) { targetStack.push(Dep.target); } Dep.target = _target; } function popTarget () { Dep.target = targetStack.pop(); } Watcher的get方法实际上就是调用了updateComponent方法,updateComponent就是 updateComponent = function() { vm._update(vm._render(), hydrating); }; 调用这个函数会接着调用_update函数更新dom,这个是挂载到vue原型的方法,而_render方法重新渲染了vnode。 Vue.prototype._render = function () { var vm = this; var ref = vm.$options; var render = ref.render; var _parentVnode = ref._parentVnode; // reset _rendered flag on slots for duplicate slot check { for (var key in vm.$slots) { // $flow-disable-line vm.$slots[key]._rendered = false; } } if (_parentVnode) { vm.$scopedSlots = _parentVnode.data.scopedSlots || emptyObject; } // set parent vnode. this allows render functions to have access // to the data on the placeholder node. vm.$vnode = _parentVnode; // render self var vnode; try { vnode = render.call(vm._renderProxy, vm.$createElement); } catch (e) { handleError(e, vm, "render"); // return error render result, // or previous vnode to prevent render error causing blank component /* istanbul ignore else */ { if (vm.$options.renderError) { try { vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e); } catch (e) { handleError(e, vm, "renderError"); vnode = vm._vnode; } } else { vnode = vm._vnode; } } } // return empty vnode in case the render function errored out if (!(vnode instanceof VNode)) { if ("development" !== 'production' && Array.isArray(vnode)) { warn( 'Multiple root nodes returned from render function. Render function ' + 'should return a single root node.', vm ); } vnode = createEmptyVNode(); } // set parent vnode.parent = _parentVnode; return vnode }; update //当依赖项改变时调用。前面有提到。 Watcher.prototype.update = function update () { var this$1 = this; /* istanbul ignore else */ //是否计算属性 if (this.computed) { if (this.dep.subs.length === 0) { this.dirty = true; } else { this.getAndInvoke(function () { this$1.dep.notify(); }); } //是否缓存 } else if (this.sync) { //调用run方法执行回调函数 this.run(); } else { queueWatcher(this); } }; Watcher.prototype.run = function run () { if (this.active) { //这里的cb就是指watcher的回调函数 this.getAndInvoke(this.cb); } }; Watcher.prototype.getAndInvoke = function getAndInvoke (cb) { var value = this.get(); if (value !== this.value ||isObject(value) ||this.deep) { //设置新的值 var oldValue = this.value; this.value = value; this.dirty = false; if (this.user) { try { cb.call(this.vm, value, oldValue); } catch (e) { handleError(e, this.vm, ("callback for watcher \"" + (this.expression) + "\"")); } } else { //执行回调函数 cb.call(this.vm, value, oldValue); } } };

猜你喜欢

转载自www.cnblogs.com/gushixianqiancheng/p/12971017.html
DEP