Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(wepy): $dirty 调用时机由 Observer 改到 Watcher,解耦 RenderWatcher 和 O… #2801

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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