Skip to content

Commit

Permalink
[FIX] context: solve tricky concurrency issue
Browse files Browse the repository at this point in the history
part of #330
  • Loading branch information
ged-odoo committed Oct 25, 2019
1 parent 3c38bbc commit 690d8ed
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 10 deletions.
29 changes: 22 additions & 7 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { onWillUnmount } from "./hooks";
export class Context extends EventBus {
state: any;
observer: Observer;
id: number = 1;
rev: number = 1;
// mapping from component id to last observed context id
mapping: { [componentId: number]: number } = {};

Expand Down Expand Up @@ -46,13 +46,13 @@ export class Context extends EventBus {
* with the same depth in parallel.
*/
async __notifyComponents() {
const id = ++this.id;
const rev = ++this.rev;
const subs = this.subscriptions.update || [];
for (let i = 0, iLen = subs.length; i < iLen; i++) {
const sub = subs[i];
const shouldCallback = sub.owner ? sub.owner.__owl__.isMounted : true;
if (shouldCallback) {
const render = sub.callback.call(sub.owner, id);
const render = sub.callback.call(sub.owner, rev);
scheduler.flush();
await render;
}
Expand All @@ -76,15 +76,30 @@ export function useContextWithCB(ctx: Context, component: Component<any, any>, m
if (id in mapping) {
return ctx.state;
}
if (!__owl__.observer) {
__owl__.observer = new Observer();
__owl__.observer.notifyCB = component.render.bind(component);
}
const currentCB = __owl__.observer.notifyCB;
__owl__.observer.notifyCB = function () {
if (ctx.rev > mapping[id]) {
// in this case, the context has been updated since we were rendering
// last, and we do not need to render here with the observer. A
// rendering is coming anyway, with the correct props.
return;
}
currentCB();
}

mapping[id] = 0;
const renderFn = __owl__.renderFn;
__owl__.renderFn = function(comp, params) {
mapping[id] = ctx.id;
mapping[id] = ctx.rev;
return renderFn(comp, params);
};
ctx.on("update", component, async contextId => {
if (mapping[id] < contextId) {
mapping[id] = contextId;
ctx.on("update", component, async contextRev => {
if (mapping[id] < contextRev) {
mapping[id] = contextRev;
await method();
}
});
Expand Down
6 changes: 3 additions & 3 deletions tests/context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ describe("Context", () => {
expect(testContext.subscriptions.update.length).toBe(0);
});

test.skip("concurrent renderings", async () => {
test("concurrent renderings", async () => {
const testContext = new Context({ x: { n: 1 }, key: "x" });
const def = makeDeferred();
let stateC;
Expand Down Expand Up @@ -207,7 +207,7 @@ describe("Context", () => {

expect(fixture.innerHTML).toBe("<div><p><span>1a</span></p></div>");
testContext.state.key = "y";
testContext.state.y = 2;
testContext.state.y = {n: 2};
delete testContext.state.x;
await nextTick();

Expand All @@ -219,6 +219,6 @@ describe("Context", () => {
def.resolve();
await nextTick();

expect(fixture.innerHTML).toBe("<div><p><span>1a</span></p></div>");
expect(fixture.innerHTML).toBe("<div><p><span>2b</span></p></div>");
});
});

0 comments on commit 690d8ed

Please sign in to comment.