[REF] component: introduce fiber

part of #293
This commit is contained in:
Géry Debongnie
2019-09-14 08:57:37 +02:00
parent 8edc637033
commit 3048c6f961
16 changed files with 190 additions and 157 deletions
+54 -21
View File
@@ -33,6 +33,19 @@ export interface Env {
[key: string]: any;
}
export interface Fiber {
force: boolean;
rootFiber: Fiber | null;
isCancelled: boolean;
scope: any;
vars: any;
// component: Component<any, any, any>;
// promises: any[];
// vnode?: VNode;
// handlers?: any;
// mountedHandlers?: any;
}
/**
* This is mostly an internal detail of implementation. The Meta interface is
* useful to typecheck and describe the internal keys used by Owl to manage the
@@ -279,8 +292,9 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
if (__owl__.isMounted) {
return;
}
const fiber = this.__createRootFiber(false);
if (!__owl__.vnode) {
const vnode = await this.__prepare();
const vnode = await this.__prepareAndRender(fiber);
if (__owl__.isDestroyed) {
// component was destroyed before we get here...
return;
@@ -288,7 +302,7 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
this.__patch(vnode);
} else if (renderBeforeRemount) {
const patchQueue = [];
await this.__render(false, patchQueue, undefined, undefined);
await this.__render(fiber, patchQueue);
this.__applyPatchQueue(<any[]>patchQueue);
}
target.appendChild(this.el!);
@@ -323,10 +337,11 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
if (!__owl__.isMounted) {
return;
}
const fiber = this.__createRootFiber(force);
const patchQueue = [];
const renderId = ++__owl__.renderId;
await this.__render(force, patchQueue, undefined, undefined);
await this.__render(fiber, patchQueue);
if (__owl__.isMounted && renderId === __owl__.renderId) {
// we only update the vnode and the actual DOM if no other rendering
@@ -335,6 +350,25 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
}
}
__createRootFiber(force): Fiber {
const fiber: Fiber = {
force,
scope: undefined,
vars: undefined,
rootFiber: null,
isCancelled: false
};
fiber.rootFiber = fiber;
return fiber;
}
__createSubFiber(parent: Fiber, scope, vars): Fiber {
const fiber = Object.create(parent);
fiber.scope = scope;
fiber.vars = vars;
return fiber;
}
/**
* Destroy the component. This operation is quite complex:
* - it recursively destroy all children
@@ -476,12 +510,12 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
*/
async __updateProps(
nextProps: Props,
forceUpdate: boolean = false,
parentFiber: Fiber,
patchQueue?: any[],
scope?: any,
vars?: any
): Promise<void> {
const shouldUpdate = forceUpdate || this.shouldUpdate(nextProps);
const shouldUpdate = parentFiber.force || this.shouldUpdate(nextProps);
if (shouldUpdate) {
const defaultProps = (<any>this.constructor).defaultProps;
if (defaultProps) {
@@ -489,7 +523,8 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
}
await this.willUpdateProps(nextProps);
this.props = nextProps;
await this.__render(forceUpdate, patchQueue, scope, vars);
const fiber = this.__createSubFiber(parentFiber, scope, vars);
await this.__render(fiber, patchQueue);
}
}
@@ -503,14 +538,20 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
__owl__.vnode = patch(target, vnode);
}
__prepare(scope?: Object, vars?: any): Promise<VNode> {
/**
* The __prepare method is only called by the t-component directive, when a
* subcomponent is created. It gets its scope and vars, if any, from the
* parent template.
*/
__prepare(parentFiber: Fiber, scope: any, vars: any): Promise<VNode> {
const __owl__ = this.__owl__;
const fiber = this.__createSubFiber(parentFiber, scope, vars);
__owl__.renderProps = this.props;
__owl__.renderPromise = this.__prepareAndRender(scope, vars);
__owl__.renderPromise = this.__prepareAndRender(fiber);
return __owl__.renderPromise;
}
async __prepareAndRender(scope?: Object, vars?: any): Promise<VNode> {
async __prepareAndRender(fiber: Fiber): Promise<VNode> {
try {
await this.willStart();
} catch (e) {
@@ -545,16 +586,10 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
}
__owl__.render = qweb.render.bind(qweb, p._template);
this.__observeState();
return this.__render(false, [], scope, vars);
return this.__render(fiber, []);
}
__render(
force: boolean = false,
patchQueue: any[] = [],
scope?: Object,
vars?: any
): Promise<VNode> {
__render(fiber: Fiber, patchQueue: any[] = []): Promise<VNode> {
const __owl__ = this.__owl__;
const promises: Promise<void>[] = [];
const patch: any[] = [this];
@@ -568,10 +603,8 @@ export class Component<T extends Env, Props extends {}, State extends {}> {
promises,
handlers: __owl__.boundHandlers,
mountedHandlers: __owl__.mountedHandlers,
forceUpdate: force,
patchQueue,
scope,
vars
fiber: fiber,
patchQueue
});
} catch (e) {
vnode = __owl__.vnode || h("div");
+8 -7
View File
@@ -441,14 +441,15 @@ QWeb.addDirective({
}
}
let scopeVars = "";
let scopeVars;
if (hasSlots) {
scopeVars += ctx.scopeVars.length ? `Object.assign({}, scope)` : varDefs.length ? `{}` : "";
if (varDefs.length) {
scopeVars += `, {${varDefs.join(",")}}`;
}
let scope = ctx.scopeVars.length ? `Object.assign({}, scope)` : `{}`;
let vars = varDefs.length ? `{${varDefs.join(",")}}` : "undefined";
scopeVars = `${scope}, ${vars}`;
} else {
scopeVars = "undefined, undefined";
}
ctx.addLine(`def${defID} = w${componentID}.__prepare(${scopeVars});`);
ctx.addLine(`def${defID} = w${componentID}.__prepare(extra.fiber, ${scopeVars});`);
// hack: specify empty remove hook to prevent the node from being removed from the DOM
let registerCode = `c${ctx.parentNode}[_${dummyID}_index]=pvnode;`;
if (shouldProxy) {
@@ -472,7 +473,7 @@ QWeb.addDirective({
ctx.addLine(`utils.validateProps(w${componentID}.constructor, props${componentID})`);
}
ctx.addLine(
`def${defID} = def${defID} || w${componentID}.__updateProps(props${componentID}, extra.forceUpdate, ${patchQueueCode}${scopeVars &&
`def${defID} = def${defID} || w${componentID}.__updateProps(props${componentID}, extra.fiber, ${patchQueueCode}${scopeVars &&
", " + scopeVars});`
);
let keepAliveCode = "";