mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
up
This commit is contained in:
+9
-4
@@ -1,9 +1,9 @@
|
|||||||
export type ExecutionContext = {
|
export type ExecutionContext = {
|
||||||
unsubcribe?: (scheduledContexts: Set<ExecutionContext>) => void;
|
unsubcribe?: (scheduledContexts: Set<ExecutionContext>) => void;
|
||||||
update: Function;
|
update: Function;
|
||||||
signals: Set<Signal>;
|
atoms: Set<Atom>;
|
||||||
getParent: () => ExecutionContext | undefined;
|
// getParent: () => ExecutionContext | undefined;
|
||||||
getChildren: () => ExecutionContext[];
|
// getChildren: () => ExecutionContext[];
|
||||||
meta: any;
|
meta: any;
|
||||||
// schedule: () => void;
|
// schedule: () => void;
|
||||||
};
|
};
|
||||||
@@ -13,6 +13,11 @@ export type customDirectives = Record<
|
|||||||
(node: Element, value: string, modifier: string[]) => void
|
(node: Element, value: string, modifier: string[]) => void
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type Signal = {
|
export type Atom = {
|
||||||
executionContexts: Set<ExecutionContext>;
|
executionContexts: Set<ExecutionContext>;
|
||||||
|
// dependents: Set<Atom>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// export type DerivedAtom = Atom & {
|
||||||
|
// dependencies: Set<Atom>;
|
||||||
|
// };
|
||||||
|
|||||||
@@ -10,20 +10,20 @@ export function getExecutionContext() {
|
|||||||
|
|
||||||
export function makeExecutionContext({
|
export function makeExecutionContext({
|
||||||
update,
|
update,
|
||||||
getParent,
|
// getParent,
|
||||||
getChildren,
|
// getChildren,
|
||||||
meta,
|
meta,
|
||||||
}: {
|
}: {
|
||||||
update: () => void;
|
update: () => void;
|
||||||
getParent?: () => ExecutionContext | undefined;
|
// getParent?: () => ExecutionContext | undefined;
|
||||||
getChildren?: () => ExecutionContext[];
|
// getChildren?: () => ExecutionContext[];
|
||||||
meta?: any;
|
meta?: any;
|
||||||
}) {
|
}) {
|
||||||
const executionContext: ExecutionContext = {
|
const executionContext: ExecutionContext = {
|
||||||
update,
|
update,
|
||||||
getParent: getParent!,
|
// getParent: getParent!,
|
||||||
getChildren: getChildren!,
|
// getChildren: getChildren!,
|
||||||
signals: new Set(),
|
atoms: new Set(),
|
||||||
meta: meta || {},
|
meta: meta || {},
|
||||||
};
|
};
|
||||||
return executionContext;
|
return executionContext;
|
||||||
|
|||||||
+76
-48
@@ -1,5 +1,5 @@
|
|||||||
import { OwlError } from "../common/owl_error";
|
import { OwlError } from "../common/owl_error";
|
||||||
import { ExecutionContext, Signal } from "../common/types";
|
import { ExecutionContext, Atom } 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
|
||||||
@@ -77,14 +77,29 @@ export function toRaw<T extends Target, U extends Reactive<T>>(value: U | T): T
|
|||||||
return targets.has(value) ? (targets.get(value) as T) : value;
|
return targets.has(value) ? (targets.get(value) as T) : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetToKeysToSignalItem = new WeakMap<Target, Map<PropertyKey, Signal>>();
|
const targetToKeysToAtomItem = new WeakMap<Target, Map<PropertyKey, Atom>>();
|
||||||
const scheduledSignals = new Set<Signal>();
|
const scheduledAtoms = new Set<Atom>();
|
||||||
|
|
||||||
function makeSignal() {
|
function makeAtom() {
|
||||||
const signal: Signal = {
|
const atom: Atom = {
|
||||||
executionContexts: new Set<ExecutionContext>(),
|
executionContexts: new Set<ExecutionContext>(),
|
||||||
|
// dependents: new Set<Atom>(),
|
||||||
};
|
};
|
||||||
return signal;
|
return atom;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTargetKeyAtom(target: Target, key: PropertyKey): Atom {
|
||||||
|
let keyToAtomItem: Map<PropertyKey, Atom> = targetToKeysToAtomItem.get(target)!;
|
||||||
|
if (!keyToAtomItem) {
|
||||||
|
keyToAtomItem = new Map();
|
||||||
|
targetToKeysToAtomItem.set(target, keyToAtomItem);
|
||||||
|
}
|
||||||
|
let atom = keyToAtomItem.get(key)!;
|
||||||
|
if (!atom) {
|
||||||
|
atom = makeAtom();
|
||||||
|
keyToAtomItem.set(key, atom);
|
||||||
|
}
|
||||||
|
return atom;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,44 +115,37 @@ function onReadTargetKey(target: Target, key: PropertyKey): void {
|
|||||||
const executionContext = getExecutionContext();
|
const executionContext = getExecutionContext();
|
||||||
if (!executionContext) return;
|
if (!executionContext) return;
|
||||||
|
|
||||||
let keyToSignalItem: Map<PropertyKey, Signal> = targetToKeysToSignalItem.get(target)!;
|
const atom = getTargetKeyAtom(target, key);
|
||||||
if (!keyToSignalItem) {
|
|
||||||
keyToSignalItem = new Map();
|
// observerAtoms.add(atom);
|
||||||
targetToKeysToSignalItem.set(target, keyToSignalItem);
|
executionContext.atoms.add(atom);
|
||||||
}
|
atom.executionContexts.add(executionContext);
|
||||||
let signal = keyToSignalItem.get(key)!;
|
|
||||||
if (!signal) {
|
|
||||||
signal = makeSignal();
|
|
||||||
keyToSignalItem.set(key, signal);
|
|
||||||
}
|
|
||||||
// observerSignals.add(signal);
|
|
||||||
executionContext.signals.add(signal);
|
|
||||||
signal.executionContexts.add(executionContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let scheduled = false;
|
let scheduled = false;
|
||||||
function scheduleSignal(signal: Signal) {
|
function scheduleAtom(atom: Atom) {
|
||||||
scheduledSignals.add(signal);
|
scheduledAtoms.add(atom);
|
||||||
|
// batched(processAtoms)();
|
||||||
if (scheduled) return;
|
if (scheduled) return;
|
||||||
scheduled = true;
|
scheduled = true;
|
||||||
Promise.resolve().then(() => {
|
Promise.resolve().then(() => {
|
||||||
scheduled = false;
|
scheduled = false;
|
||||||
processSignals();
|
processAtoms();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function processSignals() {
|
function processAtoms() {
|
||||||
const scheduledContexts = new Set(
|
const scheduledContexts = new Set(
|
||||||
[...scheduledSignals.values()].map((s) => [...s.executionContexts]).flat()
|
[...scheduledAtoms.values()].map((s) => [...s.executionContexts]).flat()
|
||||||
);
|
);
|
||||||
|
|
||||||
// schedule before context.update in case there is write operations during update
|
// schedule before context.update in case there is write operations during update
|
||||||
// todo: add a test in case there is write operations during update the test
|
// todo: add a test in case there is write operations during update the test
|
||||||
// will break is scheduledSignals.clear(); is called after context.update();
|
// will break is scheduledAtoms.clear(); is called after context.update();
|
||||||
// that writes
|
// that writes
|
||||||
scheduledSignals.clear();
|
scheduledAtoms.clear();
|
||||||
for (const ctx of [...scheduledContexts]) {
|
for (const ctx of [...scheduledContexts]) {
|
||||||
removeSignalsFromContext(ctx);
|
removeAtomsFromContext(ctx);
|
||||||
// custom unsubscribe depending on the context.
|
// custom unsubscribe depending on the context.
|
||||||
// scheduledContexts might be updated while we're iterating over it.
|
// scheduledContexts might be updated while we're iterating over it.
|
||||||
ctx.unsubcribe?.(scheduledContexts);
|
ctx.unsubcribe?.(scheduledContexts);
|
||||||
@@ -173,15 +181,15 @@ function processSignals() {
|
|||||||
* or deleted)
|
* or deleted)
|
||||||
*/
|
*/
|
||||||
function onWriteTargetKey(target: Target, key: PropertyKey): void {
|
function onWriteTargetKey(target: Target, key: PropertyKey): void {
|
||||||
const keyToSignalItem = targetToKeysToSignalItem.get(target)!;
|
const keyToAtomItem = targetToKeysToAtomItem.get(target)!;
|
||||||
if (!keyToSignalItem) {
|
if (!keyToAtomItem) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const signal = keyToSignalItem.get(key);
|
const atom = keyToAtomItem.get(key);
|
||||||
if (!signal) {
|
if (!atom) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scheduleSignal(signal);
|
scheduleAtom(atom);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maps reactive objects to the underlying target
|
// Maps reactive objects to the underlying target
|
||||||
@@ -240,31 +248,31 @@ export function reactive<T extends Target>(target: T): T {
|
|||||||
|
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
function removeSignalsFromContext(executionContext: ExecutionContext) {
|
function removeAtomsFromContext(executionContext: ExecutionContext) {
|
||||||
for (const sig of executionContext.signals) {
|
for (const sig of executionContext.atoms) {
|
||||||
sig.executionContexts.delete(executionContext);
|
sig.executionContexts.delete(executionContext);
|
||||||
}
|
}
|
||||||
executionContext.signals.clear();
|
executionContext.atoms.clear();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Unsubscribe an execution context and all its children from all signals
|
* Unsubscribe an execution context and all its children from all atoms
|
||||||
* they are subscribed to.
|
* they are subscribed to.
|
||||||
*
|
*
|
||||||
* @param executionContext the context to unsubscribe
|
* @param parentExecutionContext the context to unsubscribe
|
||||||
*/
|
*/
|
||||||
function unsubscribeChildEffect(
|
function unsubscribeChildEffect(
|
||||||
executionContext: ExecutionContext,
|
parentExecutionContext: ExecutionContext,
|
||||||
scheduledContexts: Set<ExecutionContext>
|
scheduledContexts: Set<ExecutionContext>
|
||||||
) {
|
) {
|
||||||
// executionContext.update = () => {};
|
// executionContext.update = () => {};
|
||||||
|
|
||||||
for (const children of executionContext.meta.children) {
|
for (const children of parentExecutionContext.meta.children) {
|
||||||
children.meta.parent = undefined;
|
children.meta.parent = undefined;
|
||||||
removeSignalsFromContext(children);
|
removeAtomsFromContext(children);
|
||||||
scheduledContexts.delete(children);
|
scheduledContexts.delete(children);
|
||||||
unsubscribeChildEffect(children, scheduledContexts);
|
unsubscribeChildEffect(children, scheduledContexts);
|
||||||
}
|
}
|
||||||
executionContext.meta.children.length = 0;
|
parentExecutionContext.meta.children.length = 0;
|
||||||
}
|
}
|
||||||
export function withoutReactivity<T extends (...args: any[]) => any>(fn: T): ReturnType<T> {
|
export function withoutReactivity<T extends (...args: any[]) => any>(fn: T): ReturnType<T> {
|
||||||
pushExecutionContext(undefined!);
|
pushExecutionContext(undefined!);
|
||||||
@@ -276,6 +284,7 @@ export function withoutReactivity<T extends (...args: any[]) => any>(fn: T): Ret
|
|||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function effect(fn: Function) {
|
export function effect(fn: Function) {
|
||||||
let parent = getExecutionContext();
|
let parent = getExecutionContext();
|
||||||
// todo: is it useful?
|
// todo: is it useful?
|
||||||
@@ -287,13 +296,13 @@ export function effect(fn: Function) {
|
|||||||
unsubscribeChildEffect(executionContext, scheduledContexts);
|
unsubscribeChildEffect(executionContext, scheduledContexts);
|
||||||
},
|
},
|
||||||
update: fn,
|
update: fn,
|
||||||
getParent: () => {
|
// getParent: () => {
|
||||||
return executionContext.meta.parent;
|
// return executionContext.meta.parent;
|
||||||
},
|
// },
|
||||||
getChildren: () => {
|
// getChildren: () => {
|
||||||
return executionContext.meta.children || [];
|
// return executionContext.meta.children || [];
|
||||||
},
|
// },
|
||||||
signals: new Set(),
|
atoms: new Set(),
|
||||||
meta: {
|
meta: {
|
||||||
parent: parent,
|
parent: parent,
|
||||||
children: [],
|
children: [],
|
||||||
@@ -311,6 +320,25 @@ export function effect(fn: Function) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// const dependentStack: any[][] = [];
|
||||||
|
|
||||||
|
// const derivedDependecies = new Set<Atom>();
|
||||||
|
// // const derrivedToAtom = new WeakMap<Function, Atom>();
|
||||||
|
// export function derived(fn: Function) {
|
||||||
|
// const derivedAtom: DerivedAtom = {
|
||||||
|
// executionContexts: new Set<ExecutionContext>(),
|
||||||
|
// // parent: null,
|
||||||
|
// dependencies: new Set<Atom>(),
|
||||||
|
// dependents: new Set<Atom>(),
|
||||||
|
// };
|
||||||
|
|
||||||
|
// return () => {
|
||||||
|
// dependentStack.push([]);
|
||||||
|
// fn();
|
||||||
|
// dependentStack.pop();
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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