mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[REF] component: introduce RootFiber.setCounter and update scheduler
The goal is to be able to execute code whenever a root fiber is ready, and before the next animation frame
This commit is contained in:
committed by
Samuel Degueldre
parent
d80fad760c
commit
828be28653
@@ -101,6 +101,7 @@ export class App<
|
||||
|
||||
destroy() {
|
||||
if (this.root) {
|
||||
this.scheduler.flush();
|
||||
this.root.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,8 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
|
||||
_render(fiber: Fiber | RootFiber) {
|
||||
try {
|
||||
fiber.bdom = this.renderFn();
|
||||
fiber.root!.counter--;
|
||||
const root = fiber.root!;
|
||||
root.setCounter(root.counter - 1);
|
||||
} catch (e) {
|
||||
handleError({ node: this, error: e });
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ function _handleError(node: ComponentNode | null, error: any, isFirstRound = fal
|
||||
|
||||
if (stopped) {
|
||||
if (isFirstRound && fiber && fiber.node.fiber) {
|
||||
fiber.root!.counter--;
|
||||
const root = fiber.root!;
|
||||
root.setCounter(root.counter - 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export function makeRootFiber(node: ComponentNode): Fiber {
|
||||
let current = node.fiber;
|
||||
if (current) {
|
||||
let root = current.root!;
|
||||
root.counter = root.counter + 1 - cancelFibers(current.children);
|
||||
root.setCounter(root.counter + 1 - cancelFibers(current.children));
|
||||
current.children = [];
|
||||
current.bdom = null;
|
||||
if (fibersInError.has(current)) {
|
||||
@@ -74,7 +74,7 @@ export class Fiber {
|
||||
if (parent) {
|
||||
this.deep = parent.deep;
|
||||
const root = parent.root!;
|
||||
root.counter++;
|
||||
root.setCounter(root.counter + 1);
|
||||
this.root = root;
|
||||
parent.children.push(this);
|
||||
} else {
|
||||
@@ -144,6 +144,13 @@ export class RootFiber extends Fiber {
|
||||
handleError({ fiber: current || this, error: e });
|
||||
}
|
||||
}
|
||||
|
||||
setCounter(newValue: number) {
|
||||
this.counter = newValue;
|
||||
if (newValue === 0) {
|
||||
this.node.app.scheduler.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Position = "first-child" | "last-child";
|
||||
|
||||
+26
-43
@@ -11,27 +11,15 @@ export class Scheduler {
|
||||
// interactions with other code, such as test frameworks that override them
|
||||
static requestAnimationFrame = window.requestAnimationFrame.bind(window);
|
||||
tasks: Set<RootFiber> = new Set();
|
||||
isRunning: boolean = false;
|
||||
requestAnimationFrame: Window["requestAnimationFrame"];
|
||||
frame: number = 0;
|
||||
|
||||
constructor() {
|
||||
this.requestAnimationFrame = Scheduler.requestAnimationFrame;
|
||||
}
|
||||
|
||||
start() {
|
||||
this.isRunning = true;
|
||||
this.scheduleTasks();
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.isRunning = false;
|
||||
}
|
||||
|
||||
addFiber(fiber: Fiber) {
|
||||
this.tasks.add(fiber.root!);
|
||||
if (!this.isRunning) {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,39 +27,34 @@ export class Scheduler {
|
||||
* Other tasks are left unchanged.
|
||||
*/
|
||||
flush() {
|
||||
this.tasks.forEach((fiber) => {
|
||||
if (fiber.root !== fiber) {
|
||||
this.tasks.delete(fiber);
|
||||
return;
|
||||
}
|
||||
const hasError = fibersInError.has(fiber);
|
||||
if (hasError && fiber.counter !== 0) {
|
||||
this.tasks.delete(fiber);
|
||||
return;
|
||||
}
|
||||
if (fiber.node.status === STATUS.DESTROYED) {
|
||||
this.tasks.delete(fiber);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fiber.counter === 0) {
|
||||
if (!hasError) {
|
||||
fiber.complete();
|
||||
}
|
||||
this.tasks.delete(fiber);
|
||||
}
|
||||
});
|
||||
if (this.tasks.size === 0) {
|
||||
this.stop();
|
||||
if (this.frame === 0) {
|
||||
this.frame = this.requestAnimationFrame(() => {
|
||||
this.frame = 0;
|
||||
this.tasks.forEach((fiber) => this.processFiber(fiber));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
scheduleTasks() {
|
||||
this.requestAnimationFrame(() => {
|
||||
this.flush();
|
||||
if (this.isRunning) {
|
||||
this.scheduleTasks();
|
||||
processFiber(fiber: RootFiber) {
|
||||
if (fiber.root !== fiber) {
|
||||
this.tasks.delete(fiber);
|
||||
return;
|
||||
}
|
||||
const hasError = fibersInError.has(fiber);
|
||||
if (hasError && fiber.counter !== 0) {
|
||||
this.tasks.delete(fiber);
|
||||
return;
|
||||
}
|
||||
if (fiber.node.status === STATUS.DESTROYED) {
|
||||
this.tasks.delete(fiber);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fiber.counter === 0) {
|
||||
if (!hasError) {
|
||||
fiber.complete();
|
||||
}
|
||||
});
|
||||
this.tasks.delete(fiber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user