anchors
题外
- watcher定义后会立即执行一次getter(不是cb)
this.value = this.lazy ? undefined : this.get();
- Observe里面有dep, defineReactivity里也有dep.
- defineReactive为在模型上的每个属性, 创建dep. 谁get那个属性就把target watcher添加到dep.subs里去.
- render watcher执行一次get后, 让不再引用的的属性的dep取消订阅自己.
定义响应式
定义响应式流程
- 遍历属性对象, 通过getter定义代理到vm上
- 为属性对象添加observer,
data.__ob__ = new Observer(data)
- 关系为data有dep, dep里有watcher, watcher里有dep.循环依赖?
- defineReactive内部又new dep去notify和depend, 那observer里的dep有什么用?
childOb.dep.depend();
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145initState(vm);function initState (vm) {vm._watchers = [];var opts = vm.$options;if (opts.props) { initProps(vm, opts.props); }if (opts.data) {initData(vm);} else {observe(vm._data = {}, true /* asRootData */);}if (opts.computed) { initComputed(vm, opts.computed); }if (opts.watch && opts.watch !== nativeWatch) {initWatch(vm, opts.watch);}}function initData (vm) {var data = vm._data = vm.$options.datavar keys = Object.keys(data);var i = keys.length;while (i--) {var key = keys[i];proxy(vm, "_data", key);}// observe data 定义响应式observe(data, true /* asRootData */);}function observe (value, asRootData) {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}var Observer = function Observer (value) {this.value = value;this.dep = new Dep(); // dep.subs收集watcherthis.vmCount = 0;def(value, '__ob__', this); // 不可枚举属性if (Array.isArray(value)) {var augment = hasProto? protoAugment: copyAugment;augment(value, arrayMethods, arrayKeys);this.observeArray(value);} else {this.walk(value);}};/*** Walk through each property and convert them into* getter/setters. This method should only be called when* value type is Object.*/Observer.prototype.walk = function walk (obj) {var keys = Object.keys(obj);for (var i = 0; i < keys.length; i++) {defineReactive(obj, keys[i]);}};/*** Observe a list of Array items.*/Observer.prototype.observeArray = function observeArray (items) {for (var i = 0, l = items.length; i < l; i++) {observe(items[i]);}};function defineReactive (obj,key,val,customSetter,shallow) {var dep = new Dep();var property = Object.getOwnPropertyDescriptor(obj, key);if (property && property.configurable === false) {return}// cater for pre-defined getter/settersvar getter = property && property.get;if (!getter && arguments.length === 2) {val = obj[key];}var setter = property && property.set;var childOb = !shallow && observe(val);Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter () {var value = getter ? getter.call(obj) : val;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 (process.env.NODE_ENV !== 'production' && customSetter) {customSetter();}if (setter) {setter.call(obj, newVal);} else {val = newVal;}childOb = !shallow && observe(newVal);dep.notify();}});}
|
|
user-watcher响应式流程
user定义的watch在initState时通过$watch创建并放入
vm._watchers
, renderWatcher在vm.$mount
创建, watcher创建晚于defineReactivity这样, 在get属性的时候就能访问属性的getters收集依赖123456function initState (vm) {// props data computed reactivityif (opts.watch && opts.watch !== nativeWatch) {initWatch(vm, opts.watch); // => createWatcher(vm, key, handler); => vm.$watch(expOrFn, handler, options) => var watcher = new Watcher(vm, expOrFn, cb, options);}}user watcher在创建后访问getter, 此时Dep.target是user watcher, expOrFun
123456789101112131415161718192021222324252627282930313233343536373839404142434445get: function reactiveGetter () {var value = getter ? getter.call(obj) : val;if (Dep.target) {dep.depend();if (childOb) {childOb.dep.depend();if (Array.isArray(value)) {dependArray(value);}}}return value}Dep.prototype.depend = function depend () {if (Dep.target) {Dep.target.addDep(this);}};Watcher.prototype.addDep = function addDep (dep) {var id = dep.id;if (!this.newDepIds.has(id)) {this.newDepIds.add(id);this.newDeps.push(dep);if (!this.depIds.has(id)) {dep.addSub(this);}}};// depend过后, user watcher会有如下数据, 的确是循环引用Dep.target.deps = [dep : {sub : `user watcher`},dep : { // "defineReactive person.name dep"sub : `user watcher`},dep : { // "defineReactive person dep"sub : `user watcher`},dep : { // "person.data observer dep"sub : `user watcher`}]
依赖收集
|
|
- Watcher的get 收集依赖后, 调用取消视图上不再依赖的dep.subs注册.
|
|
派发更新
- 让defineReactive里的dep执行notify, notify遍历subs watcher, 并调用update
- render watch的before钩子执行before update
- callUpdatedHooks(updatedQueue);执行updatedhook
- user cb调用条件
(value !== this.value || isObject(value) || this.deep)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748Dep.prototype.notify = function notify () {var subs = this.subs.slice();if (process.env.NODE_ENV !== 'production' && !config.async) {// subs aren't sorted in scheduler if not running async// we need to sort them now to make sure they fire in correct// ordersubs.sort(function (a, b) { return a.id - b.id; });}for (var i = 0, l = subs.length; i < l; i++) {subs[i].update();}};// 加入队列Watcher.prototype.update = function update () {/* istanbul ignore else */if (this.lazy) {this.dirty = true;} else if (this.sync) {this.run();} else {queueWatcher(this);}};function queueWatcher (watcher) {var id = watcher.id;if (has[id] == null) {has[id] = true;if (!flushing) {queue.push(watcher);} else {// if already flushing, splice the watcher based on its id// if already past its id, it will be run next immediately.var i = queue.length - 1;while (i > index && queue[i].id > watcher.id) {i--;}queue.splice(i + 1, 0, watcher);}// queue the flushif (!waiting) {waiting = true;// 异步刷队列前可以不停加任务nextTick(flushSchedulerQueue);}}}
|
|
vue-nextTick
- 默认micro task用messageChannel?
- $nextTick调用的先后,也就是cb执行顺序. 设置值会立即添加到队列.
|
|
手动设置响应式和数组响应式
{} []
上都会创建observer, object会对每个key- setter里让watcher 添加到dep的subs里.
observer里dep的作用, 为了set触发渲染watcher的重新渲染。
12345678910111213141516171819202122232425function set (target, key, val) {var ob = (target).__ob__;defineReactive(ob.value, key, val);ob.dep.notify();return val}var childOb = !shallow && observe(val); // 子属性依赖创建observerObject.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter () {var value = getter ? getter.call(obj) : val;if (Dep.target) {dep.depend();if (childOb) {childOb.dep.depend(); // 收集子属性依赖if (Array.isArray(value)) {dependArray(value);}}}return value},数组响应式方法
|
|