Skip to content

Commit

Permalink
refactor(wepy): $dirty 调用时机由 Observer 改到 Watcher,解耦 RenderWatcher 和 O…
Browse files Browse the repository at this point in the history
…bserver
  • Loading branch information
nishino-tsukasa committed May 22, 2022
1 parent 84f1927 commit 17d0ac6
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 91 deletions.
19 changes: 17 additions & 2 deletions packages/core/test/weapp/class/Dirty.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { initData } from '../../../weapp/init/data';
import Dirty from '../../../weapp/class/Dirty';
import { initRender } from '../../../weapp/init/render';

const expect = require('chai').expect;

describe('weapp class Dirty', function() {
it('test dirty path', () => {
const vm = {};
const vm = {
_watchers: []
};
vm.$dirty = new Dirty('path');

initData(vm, { list: [], num: 1, arr: [1, 2], complex: { a: 1, arr: [100, { x: [0, 1, { b: 1 }] }] } });
initRender(
vm,
Object.keys(vm._data),
Object.keys({})
);

vm.num = 2;
expect(vm.$dirty.length()).to.be.equal(1);
Expand Down Expand Up @@ -49,10 +57,17 @@ describe('weapp class Dirty', function() {
});

it('test dirty key', () => {
const vm = {};
const vm = {
_watchers: []
};
vm.$dirty = new Dirty('key');

initData(vm, { num: 1, arr: [1, 2], complex: { a: 1, arr: [100, { x: [0, 1, { b: 1 }] }] } });
initRender(
vm,
Object.keys(vm._data),
Object.keys({})
);

vm.num = 2;
expect(vm.$dirty.length()).to.be.equal(1);
Expand Down
4 changes: 2 additions & 2 deletions packages/core/weapp/class/Dirty.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default class Dirty {
/**
* Set dirty from a ObserverPath
*/
set(op, key, value) {
set(op, key, value, vm) {
let pathMap;
let pathKeys;
// eslint-disable-next-line eqeqeq
Expand All @@ -53,7 +53,7 @@ export default class Dirty {
* 因此不需要所有 path 都 setData 。
*/
const { root, path } = pathMap[pathKeys[0]];
this.push(root, path, root === path ? value : op.ob.vm[root], value);
this.push(root, path, root === path ? value : vm[root], value);
}

reset() {
Expand Down
6 changes: 4 additions & 2 deletions packages/core/weapp/class/WepyComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Base from './Base';
import Watcher from '../observer/watcher';
import { isArr, isPlainObject } from '../../shared/index';

import { renderNextTick } from '../util/next-tick';
import { renderNextTick, nextTick } from '../util/next-tick';

export default class WepyComponent extends Base {
$watch(expOrFn, cb, options) {
Expand All @@ -24,7 +24,9 @@ export default class WepyComponent extends Base {
options.user = true;
let watcher = new Watcher(vm, expOrFn, cb, options);
if (options.immediate) {
cb.call(vm, watcher.value);
nextTick(function() {
cb.call(vm, watcher.value);
});
}
return function unwatchFn() {
watcher.teardown();
Expand Down
18 changes: 8 additions & 10 deletions packages/core/weapp/observer/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,21 @@ methodsToPatch.forEach(function(method) {

const result = original.apply(this, args);
const ob = this.__ob__;
const vm = ob.vm;

// push parent key to dirty, wait to setData
if (vm.$dirty) {
if (method === 'push') {
const lastIndex = ob.value.length - 1;
vm.$dirty.set(ob.op, lastIndex, ob.value[lastIndex]);
} else {
vm.$dirty.set(ob.op, null, ob.value);
}
let dirtyData;

if (method === 'push') {
const lastIndex = ob.value.length - 1;
dirtyData = { op: ob.op, key: lastIndex, value: ob.value[lastIndex] }
} else {
dirtyData = { op: ob.op, key: null, value: ob.value }
}

// 这里和 vue 不一样,所有变异方法都需要更新 path
ob.observeArray(ob.key, ob.value);

// notify change
ob.dep.notify();
ob.dep.notify({ dirtyData });
return result;
});
});
Expand Down
4 changes: 2 additions & 2 deletions packages/core/weapp/observer/dep.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ export default class Dep {
}
}

notify() {
notify(obj) {
// stabilize the subscriber list first
const subs = this.subs.slice();
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update();
subs[i].update(obj);
}
}
}
Expand Down
86 changes: 14 additions & 72 deletions packages/core/weapp/observer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ export const observerState = {
* collect dependencies and dispatches updates.
*/
export class Observer {
constructor({ vm, key, value, parent }) {
constructor({ key, value, parent }) {
this.value = value;
this.dep = new Dep();
this.vmCount = 0;
this.vm = vm;
this.op = new ObserverPath(key, this, parent && parent.__ob__ && parent.__ob__.op);

def(value, '__ob__', this);
Expand All @@ -47,7 +46,7 @@ export class Observer {
walk(key, obj) {
const keys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {
defineReactive({ vm: this.vm, obj: obj, key: keys[i], value: obj[keys[i]], parent: obj });
defineReactive({ obj: obj, key: keys[i], value: obj[keys[i]], parent: obj });
//defineReactive(this.vm, obj, keys[i], obj[keys[i]]);
}
}
Expand All @@ -57,56 +56,9 @@ export class Observer {
*/
observeArray(key, items) {
for (let i = 0, l = items.length; i < l; i++) {
observe({ vm: this.vm, key: i, value: items[i], parent: items });
observe({ key: i, value: items[i], parent: items });
}
}

/**
* Check if path exsit in vm
*/
hasPath(path) {
let value = this.vm;
let key = '';
let i = 0;
while (i < path.length) {
if (path[i] !== '.' && path[i] !== '[' && path[i] !== ']') {
key += path[i];
} else if (key.length !== 0) {
value = value[key];
key = '';
if (!isObject(value)) {
return false;
}
}
i++;
}
return true;
}

/**
* Is this path value equal
*/
isPathEq(path, value) {
let objValue = this.vm;
let key = '';
let i = 0;
while (i < path.length) {
if (path[i] !== '.' && path[i] !== '[' && path[i] !== ']') {
key += path[i];
} else if (key.length !== 0) {
objValue = objValue[key];
key = '';
if (!isObject(objValue)) {
return false;
}
}
i++;
}
if (key.length !== 0) {
objValue = objValue[key];
}
return value === objValue;
}
}

// helpers
Expand Down Expand Up @@ -138,7 +90,7 @@ function copyAugment(target, src, keys) {
* returns the new observer if successfully observed,
* or the existing observer if the value already has one.
*/
export function observe({ vm, key, value, parent, root }) {
export function observe({ key, value, parent, root }) {
if (!isObject(value)) {
return;
}
Expand All @@ -153,7 +105,7 @@ export function observe({ vm, key, value, parent, root }) {
Object.isExtensible(value) &&
!value._isVue
) {
ob = new Observer({ vm: vm, key: key, value: value, parent: parent });
ob = new Observer({ key: key, value: value, parent: parent });
}
if (root && ob) {
ob.vmCount++;
Expand All @@ -164,7 +116,7 @@ export function observe({ vm, key, value, parent, root }) {
/**
* Define a reactive property on an Object.
*/
export function defineReactive({ vm, obj, key, value, parent, customSetter, shallow }) {
export function defineReactive({ obj, key, value, parent, customSetter, shallow }) {
const dep = new Dep();

const property = Object.getOwnPropertyDescriptor(obj, key);
Expand All @@ -179,7 +131,7 @@ export function defineReactive({ vm, obj, key, value, parent, customSetter, shal
}
const setter = property && property.set;

let childOb = !shallow && observe({ vm: vm, key: key, value: value, parent: obj });
let childOb = !shallow && observe({ key: key, value: value, parent: obj });
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
Expand Down Expand Up @@ -221,15 +173,8 @@ export function defineReactive({ vm, obj, key, value, parent, customSetter, shal
value = newVal;
}

// Have to set dirty after value assigned, otherwise the dirty key is incrrect.
if (vm) {
// push parent key to dirty, wait to setData
if (vm.$dirty) {
vm.$dirty.set(obj.__ob__.op, key, newVal);
}
}
childOb = !shallow && observe({ vm: vm, key: key, value: newVal, parent: parent });
dep.notify();
childOb = !shallow && observe({ key: key, value: newVal, parent: parent });
dep.notify({ dirtyData: { op: obj.__ob__.op, key: key, value: newVal } });
}
});
}
Expand Down Expand Up @@ -270,14 +215,11 @@ export function set(vm, target, key, val) {
// delete invalid paths
cleanPaths(key, target[key].__ob__.op, ob.op);
}
defineReactive({ vm: vm, obj: ob.value, key: key, value: val, parent: ob.value });
if (vm) {
// push parent key to dirty, wait to setData
if (vm.$dirty && hasOwn(target, '__ob__')) {
vm.$dirty.set(target.__ob__.op, key, val);
}
}
ob.dep.notify();

defineReactive({ obj: ob.value, key: key, value: val, parent: ob.value });

ob.dep.notify({ dirtyData: { op: ob.op, key: key, value: val } });

return val;
}

Expand Down
6 changes: 5 additions & 1 deletion packages/core/weapp/observer/watcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,11 @@ export default class Watcher {
* Subscriber interface.
* Will be called when a dependency changes.
*/
update() {
update(obj = {}) {
if (this.isRenderWatcher && obj.dirtyData) {
this.vm.$dirty.set(obj.dirtyData.op, obj.dirtyData.key, obj.dirtyData.value, this.vm)
}

/* istanbul ignore else */
if (this.computed) {
this.dirty = true;
Expand Down

0 comments on commit 17d0ac6

Please sign in to comment.