mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
up
This commit is contained in:
+12
-7
@@ -1,10 +1,11 @@
|
|||||||
export type ExecutionContext = {
|
export type ExecutionContext = {
|
||||||
|
onReadAtom: (atom: Atom) => void;
|
||||||
unsubcribe?: (scheduledContexts: Set<ExecutionContext>) => void;
|
unsubcribe?: (scheduledContexts: Set<ExecutionContext>) => void;
|
||||||
update: Function;
|
update?: Function;
|
||||||
atoms: Set<Atom>;
|
atoms?: Set<Atom>;
|
||||||
|
meta?: any;
|
||||||
// getParent: () => ExecutionContext | undefined;
|
// getParent: () => ExecutionContext | undefined;
|
||||||
// getChildren: () => ExecutionContext[];
|
// getChildren: () => ExecutionContext[];
|
||||||
meta: any;
|
|
||||||
// schedule: () => void;
|
// schedule: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -15,9 +16,13 @@ export type customDirectives = Record<
|
|||||||
|
|
||||||
export type Atom = {
|
export type Atom = {
|
||||||
executionContexts: Set<ExecutionContext>;
|
executionContexts: Set<ExecutionContext>;
|
||||||
// dependents: Set<Atom>;
|
dependents: Set<DerivedAtom>;
|
||||||
|
getValue: () => any;
|
||||||
};
|
};
|
||||||
|
|
||||||
// export type DerivedAtom = Atom & {
|
export type OldValue = any;
|
||||||
// dependencies: Set<Atom>;
|
|
||||||
// };
|
export type DerivedAtom = Atom & {
|
||||||
|
dependencies: Map<Atom, OldValue>;
|
||||||
|
computed: boolean;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { OwlError } from "../common/owl_error";
|
import { OwlError } from "../common/owl_error";
|
||||||
import { ExecutionContext } from "../common/types";
|
import { Atom, ExecutionContext } from "../common/types";
|
||||||
import type { App, Env } from "./app";
|
import type { App, Env } from "./app";
|
||||||
import { BDom, VNode } from "./blockdom";
|
import { BDom, VNode } from "./blockdom";
|
||||||
import { makeTaskContext, TaskContext } from "./cancellableContext";
|
import { makeTaskContext, TaskContext } from "./cancellableContext";
|
||||||
import { Component, ComponentConstructor, Props } from "./component";
|
import { Component, ComponentConstructor, Props } from "./component";
|
||||||
import { fibersInError } from "./error_handling";
|
import { fibersInError } from "./error_handling";
|
||||||
import { makeExecutionContext } from "./executionContext";
|
|
||||||
import { Fiber, makeChildFiber, makeRootFiber, MountFiber, MountOptions } from "./fibers";
|
import { Fiber, makeChildFiber, makeRootFiber, MountFiber, MountOptions } from "./fibers";
|
||||||
import { reactive, targets, withoutReactivity } from "./reactivity";
|
import { addAtomToContext, reactive, targets, withoutReactivity } from "./reactivity";
|
||||||
import { STATUS } from "./status";
|
import { STATUS } from "./status";
|
||||||
|
|
||||||
let currentNode: ComponentNode | null = null;
|
let currentNode: ComponentNode | null = null;
|
||||||
@@ -106,16 +105,14 @@ export class ComponentNode<P extends Props = any, E = any> implements VNode<Comp
|
|||||||
this.props = props;
|
this.props = props;
|
||||||
this.parentKey = parentKey;
|
this.parentKey = parentKey;
|
||||||
this.taskContext = makeTaskContext();
|
this.taskContext = makeTaskContext();
|
||||||
this.executionContext = makeExecutionContext({
|
this.executionContext = {
|
||||||
|
meta: this,
|
||||||
update: () => {
|
update: () => {
|
||||||
this.render(false);
|
this.render(false);
|
||||||
},
|
},
|
||||||
getParent: () => this.parent?.executionContext,
|
onReadAtom: (atom: Atom) => addAtomToContext(atom, this.executionContext),
|
||||||
getChildren: () => {
|
atoms: new Set<Atom>(),
|
||||||
return Object.values(this.children).map((c) => c.executionContext);
|
};
|
||||||
},
|
|
||||||
meta: this,
|
|
||||||
});
|
|
||||||
const defaultProps = C.defaultProps;
|
const defaultProps = C.defaultProps;
|
||||||
props = Object.assign({}, props);
|
props = Object.assign({}, props);
|
||||||
if (defaultProps) {
|
if (defaultProps) {
|
||||||
@@ -123,12 +120,12 @@ export class ComponentNode<P extends Props = any, E = any> implements VNode<Comp
|
|||||||
}
|
}
|
||||||
const env = (parent && parent.childEnv) || app.env;
|
const env = (parent && parent.childEnv) || app.env;
|
||||||
this.childEnv = env;
|
this.childEnv = env;
|
||||||
for (const key in props) {
|
// for (const key in props) {
|
||||||
const prop = props[key];
|
// const prop = props[key];
|
||||||
if (prop && typeof prop === "object" && targets.has(prop)) {
|
// if (prop && typeof prop === "object" && targets.has(prop)) {
|
||||||
props[key] = useState(prop);
|
// props[key] = useState(prop);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
this.component = new C(props, env, this);
|
this.component = new C(props, env, this);
|
||||||
const ctx = Object.assign(Object.create(this.component), { this: this.component });
|
const ctx = Object.assign(Object.create(this.component), { this: this.component });
|
||||||
this.renderFn = app.getTemplate(C.template).bind(this.component, ctx, this);
|
this.renderFn = app.getTemplate(C.template).bind(this.component, ctx, this);
|
||||||
@@ -271,12 +268,12 @@ export class ComponentNode<P extends Props = any, E = any> implements VNode<Comp
|
|||||||
}
|
}
|
||||||
|
|
||||||
currentNode = this;
|
currentNode = this;
|
||||||
for (const key in props) {
|
// for (const key in props) {
|
||||||
const prop = props[key];
|
// const prop = props[key];
|
||||||
if (prop && typeof prop === "object" && targets.has(prop)) {
|
// if (prop && typeof prop === "object" && targets.has(prop)) {
|
||||||
props[key] = useState(prop);
|
// props[key] = useState(prop);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
currentNode = null;
|
currentNode = null;
|
||||||
let prom: Promise<any[]>;
|
let prom: Promise<any[]>;
|
||||||
withoutReactivity(() => {
|
withoutReactivity(() => {
|
||||||
|
|||||||
@@ -8,27 +8,6 @@ export function getExecutionContext() {
|
|||||||
return executionContexts[executionContexts.length - 1];
|
return executionContexts[executionContexts.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeExecutionContext({
|
|
||||||
update,
|
|
||||||
// getParent,
|
|
||||||
// getChildren,
|
|
||||||
meta,
|
|
||||||
}: {
|
|
||||||
update: () => void;
|
|
||||||
// getParent?: () => ExecutionContext | undefined;
|
|
||||||
// getChildren?: () => ExecutionContext[];
|
|
||||||
meta?: any;
|
|
||||||
}) {
|
|
||||||
const executionContext: ExecutionContext = {
|
|
||||||
update,
|
|
||||||
// getParent: getParent!,
|
|
||||||
// getChildren: getChildren!,
|
|
||||||
atoms: new Set(),
|
|
||||||
meta: meta || {},
|
|
||||||
};
|
|
||||||
return executionContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pushExecutionContext(context: ExecutionContext) {
|
export function pushExecutionContext(context: ExecutionContext) {
|
||||||
executionContexts.push(context);
|
executionContexts.push(context);
|
||||||
}
|
}
|
||||||
@@ -37,11 +16,11 @@ export function popExecutionContext() {
|
|||||||
executionContexts.pop();
|
executionContexts.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeExecutionContext({ update, meta }: { update: () => void; meta?: any }) {
|
// export function makeExecutionContext({ update, meta }: { update: () => void; meta?: any }) {
|
||||||
const executionContext: ExecutionContext = {
|
// const executionContext: ExecutionContext = {
|
||||||
update,
|
// update,
|
||||||
atoms: new Set(),
|
// atoms: new Set(),
|
||||||
meta: meta || {},
|
// meta: meta || {},
|
||||||
};
|
// };
|
||||||
return executionContext;
|
// return executionContext;
|
||||||
}
|
// }
|
||||||
|
|||||||
+57
-35
@@ -1,5 +1,5 @@
|
|||||||
import { OwlError } from "../common/owl_error";
|
import { OwlError } from "../common/owl_error";
|
||||||
import { ExecutionContext, Atom } from "../common/types";
|
import { ExecutionContext, Atom, DerivedAtom, OldValue } from "../common/types";
|
||||||
import { getExecutionContext, popExecutionContext, pushExecutionContext } from "./executionContext";
|
import { getExecutionContext, popExecutionContext, pushExecutionContext } from "./executionContext";
|
||||||
|
|
||||||
// Special key to subscribe to, to be notified of key creation/deletion
|
// Special key to subscribe to, to be notified of key creation/deletion
|
||||||
@@ -80,10 +80,11 @@ export function toRaw<T extends Target, U extends Reactive<T>>(value: U | T): T
|
|||||||
const targetToKeysToAtomItem = new WeakMap<Target, Map<PropertyKey, Atom>>();
|
const targetToKeysToAtomItem = new WeakMap<Target, Map<PropertyKey, Atom>>();
|
||||||
const scheduledAtoms = new Set<Atom>();
|
const scheduledAtoms = new Set<Atom>();
|
||||||
|
|
||||||
function makeAtom() {
|
function makeAtom(getValue: () => any): Atom {
|
||||||
const atom: Atom = {
|
const atom: Atom = {
|
||||||
executionContexts: new Set<ExecutionContext>(),
|
executionContexts: new Set<ExecutionContext>(),
|
||||||
// dependents: new Set<Atom>(),
|
dependents: new Set<Atom>(),
|
||||||
|
// getValue,
|
||||||
};
|
};
|
||||||
return atom;
|
return atom;
|
||||||
}
|
}
|
||||||
@@ -96,12 +97,17 @@ function getTargetKeyAtom(target: Target, key: PropertyKey): Atom {
|
|||||||
}
|
}
|
||||||
let atom = keyToAtomItem.get(key)!;
|
let atom = keyToAtomItem.get(key)!;
|
||||||
if (!atom) {
|
if (!atom) {
|
||||||
atom = makeAtom();
|
atom = makeAtom(() => Reflect.get(target, key));
|
||||||
keyToAtomItem.set(key, atom);
|
keyToAtomItem.set(key, atom);
|
||||||
}
|
}
|
||||||
return atom;
|
return atom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function addAtomToContext(atom: Atom, executionContext: ExecutionContext) {
|
||||||
|
executionContext.atoms.add(atom);
|
||||||
|
atom.executionContexts.add(executionContext);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observes a given key on a target with an callback. The callback will be
|
* Observes a given key on a target with an callback. The callback will be
|
||||||
* called when the given key changes on the target.
|
* called when the given key changes on the target.
|
||||||
@@ -111,15 +117,9 @@ function getTargetKeyAtom(target: Target, key: PropertyKey): Atom {
|
|||||||
* or deletion)
|
* or deletion)
|
||||||
* @param callback the function to call when the key changes
|
* @param callback the function to call when the key changes
|
||||||
*/
|
*/
|
||||||
function onReadTargetKey(target: Target, key: PropertyKey): void {
|
function onReadTargetKey(target: Target, key: PropertyKey, receiver: any): void {
|
||||||
const executionContext = getExecutionContext();
|
const executionContext = getExecutionContext();
|
||||||
if (!executionContext) return;
|
executionContext?.onReadAtom(getTargetKeyAtom(target, key));
|
||||||
|
|
||||||
const atom = getTargetKeyAtom(target, key);
|
|
||||||
|
|
||||||
// observerAtoms.add(atom);
|
|
||||||
executionContext.atoms.add(atom);
|
|
||||||
atom.executionContexts.add(executionContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let scheduled = false;
|
let scheduled = false;
|
||||||
@@ -134,7 +134,20 @@ function scheduleAtom(atom: Atom) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function processDerivedAtoms() {
|
||||||
|
const processedAtoms = new Set<Atom>();
|
||||||
|
for (const atom of scheduledAtoms) {
|
||||||
|
for (const dep of atom.dependents) {
|
||||||
|
if (processedAtoms.has(dep)) continue;
|
||||||
|
dep.computed = false;
|
||||||
|
processedAtoms.add(dep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function processAtoms() {
|
function processAtoms() {
|
||||||
|
processDerivedAtoms();
|
||||||
|
|
||||||
const scheduledContexts = new Set(
|
const scheduledContexts = new Set(
|
||||||
[...scheduledAtoms.values()].map((s) => [...s.executionContexts]).flat()
|
[...scheduledAtoms.values()].map((s) => [...s.executionContexts]).flat()
|
||||||
);
|
);
|
||||||
@@ -154,7 +167,7 @@ function processAtoms() {
|
|||||||
for (const context of scheduledContexts) {
|
for (const context of scheduledContexts) {
|
||||||
pushExecutionContext(context);
|
pushExecutionContext(context);
|
||||||
try {
|
try {
|
||||||
context.update();
|
context.update?.();
|
||||||
} finally {
|
} finally {
|
||||||
popExecutionContext();
|
popExecutionContext();
|
||||||
}
|
}
|
||||||
@@ -296,12 +309,7 @@ export function effect(fn: Function) {
|
|||||||
unsubscribeChildEffect(executionContext, scheduledContexts);
|
unsubscribeChildEffect(executionContext, scheduledContexts);
|
||||||
},
|
},
|
||||||
update: fn,
|
update: fn,
|
||||||
// getParent: () => {
|
onReadAtom: (atom: Atom) => addAtomToContext(atom, executionContext),
|
||||||
// return executionContext.meta.parent;
|
|
||||||
// },
|
|
||||||
// getChildren: () => {
|
|
||||||
// return executionContext.meta.children || [];
|
|
||||||
// },
|
|
||||||
atoms: new Set(),
|
atoms: new Set(),
|
||||||
meta: {
|
meta: {
|
||||||
parent: parent,
|
parent: parent,
|
||||||
@@ -320,24 +328,38 @@ export function effect(fn: Function) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// const dependentStack: any[][] = [];
|
export function derived(fn: Function) {
|
||||||
|
let lastValue: any;
|
||||||
|
|
||||||
// const derivedDependecies = new Set<Atom>();
|
const derivedAtom: DerivedAtom = {
|
||||||
// // const derrivedToAtom = new WeakMap<Function, Atom>();
|
executionContexts: new Set<ExecutionContext>(),
|
||||||
// export function derived(fn: Function) {
|
dependents: new Set<Atom>(),
|
||||||
// const derivedAtom: DerivedAtom = {
|
dependencies: new Map<Atom, OldValue>(),
|
||||||
// executionContexts: new Set<ExecutionContext>(),
|
getValue: () => lastValue,
|
||||||
// // parent: null,
|
computed: false,
|
||||||
// dependencies: new Set<Atom>(),
|
};
|
||||||
// dependents: new Set<Atom>(),
|
|
||||||
// };
|
|
||||||
|
|
||||||
// return () => {
|
return () => {
|
||||||
// dependentStack.push([]);
|
const executionContext = getExecutionContext();
|
||||||
// fn();
|
executionContext?.onReadAtom(derivedAtom);
|
||||||
// dependentStack.pop();
|
if (derivedAtom.computed) return lastValue;
|
||||||
// };
|
|
||||||
// }
|
const derivedExecutionContext: ExecutionContext = {
|
||||||
|
onReadAtom: (atom: Atom) => {
|
||||||
|
atom.dependents.add(derivedAtom);
|
||||||
|
// derivedAtom.executionContexts.add(executionContext);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
pushExecutionContext(derivedExecutionContext);
|
||||||
|
try {
|
||||||
|
lastValue = fn();
|
||||||
|
} finally {
|
||||||
|
popExecutionContext();
|
||||||
|
}
|
||||||
|
derivedAtom.computed = true;
|
||||||
|
return lastValue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a basic proxy handler for regular objects and arrays.
|
* Creates a basic proxy handler for regular objects and arrays.
|
||||||
|
|||||||
Reference in New Issue
Block a user