From 94e7d9aa39e6761d14dcf0acb8f49aaba1a419ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 17 Apr 2019 09:16:19 +0200 Subject: [PATCH] [REF] observer: move batch code out of store, add notifycb --- src/observer.ts | 19 ++++++++++++++++--- src/store.ts | 12 +----------- tests/observer.test.ts | 27 +++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/observer.ts b/src/observer.ts index 5ecd71c4..ba1a8acf 100644 --- a/src/observer.ts +++ b/src/observer.ts @@ -18,7 +18,7 @@ const ModifiedArrayProto = Object.create(ArrayProto); for (let method of methodsToPatch) { const initialMethod = ArrayProto[method]; ModifiedArrayProto[method] = function(...args) { - this.__observer__.rev++; + this.__observer__.notifyChange(); this.__owl__.rev++; let parent = this; do { @@ -46,6 +46,19 @@ for (let method of methodsToPatch) { export class Observer { rev: number = 1; allowMutations: boolean = true; + dirty: boolean = false; + + notifyCB() {} + notifyChange() { + this.rev++; + this.dirty = true; + Promise.resolve().then(() => { + if (this.dirty) { + this.dirty = false; + this.notifyCB(); + } + }); + } observe(value: any, parent?: any) { if (value === null) { @@ -69,7 +82,7 @@ export class Observer { set(target: any, key: number | string, value: any) { this._addProp(target, key, value); target.__owl__.rev++; - this.rev++; + this.notifyChange(); } unobserve(target: any) { @@ -119,11 +132,11 @@ export class Observer { value = newVal; self.observe(newVal, obj); obj.__owl__.rev!++; - self.rev++; let parent = obj; do { parent.__owl__.deepRev++; } while ((parent = parent.__owl__.parent)); + self.notifyChange(); } } }); diff --git a/src/store.ts b/src/store.ts index 03d2546f..c9e0b6ec 100644 --- a/src/store.ts +++ b/src/store.ts @@ -22,7 +22,6 @@ export class Store extends EventBus { actions: any; mutations: any; _commitLevel: number = 0; - _isMutating: boolean = false; history: any[] = []; debug: boolean; env: any; @@ -37,6 +36,7 @@ export class Store extends EventBus { this.mutations = config.mutations; this.env = config.env; this.observer = new Observer(); + this.observer.notifyCB = this.trigger.bind(this, "update"); this.observer.allowMutations = false; this.observer.observe(this.state); @@ -72,8 +72,6 @@ export class Store extends EventBus { throw new Error(`[Error] mutation ${type} is undefined`); } this._commitLevel++; - const currentRev = this.observer.rev; - this._isMutating = true; this.observer.allowMutations = true; const res = this.mutations[type].call( @@ -95,14 +93,6 @@ export class Store extends EventBus { payload: payload }); } - Promise.resolve().then(() => { - if (this._isMutating) { - this._isMutating = false; - if (currentRev !== this.observer.rev) { - this.trigger("update", this.state); - } - } - }); } this._commitLevel--; return res; diff --git a/tests/observer.test.ts b/tests/observer.test.ts index 1e7dc908..f04f0f71 100644 --- a/tests/observer.test.ts +++ b/tests/observer.test.ts @@ -1,4 +1,5 @@ import { Observer } from "../src/observer"; +import { nextMicroTick } from "./helpers"; describe("observer", () => { test("properly observe objects", () => { @@ -252,4 +253,30 @@ describe("observer", () => { expect(obj1.__owl__.rev).toBe(1); expect(obj2.__owl__.rev).toBe(2); }); + + test("call callback when state is changed", async () => { + const observer = new Observer(); + observer.notifyCB = jest.fn(); + const obj: any = { a: 1, b: { c: 2 }, d: [{ e: 3 }], f: 4 }; + + observer.observe(obj); + expect(observer.notifyCB).toBeCalledTimes(0); + + obj.a = 2; + await nextMicroTick(); + expect(observer.notifyCB).toBeCalledTimes(1); + + obj.b.c = 3; + await nextMicroTick(); + expect(observer.notifyCB).toBeCalledTimes(2); + + obj.d[0].e = 5; + await nextMicroTick(); + expect(observer.notifyCB).toBeCalledTimes(3); + + obj.a = 111; + obj.f = 222; + await nextMicroTick(); + expect(observer.notifyCB).toBeCalledTimes(4); + }); });