mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[REF] utils: move batched from reactivity to utils
This commit is contained in:
committed by
Samuel Degueldre
parent
6091912c54
commit
45f6a8e97a
+1
-25
@@ -1,5 +1,6 @@
|
|||||||
import { onWillUnmount } from "./component/lifecycle_hooks";
|
import { onWillUnmount } from "./component/lifecycle_hooks";
|
||||||
import { ComponentNode, getCurrent } from "./component/component_node";
|
import { ComponentNode, getCurrent } from "./component/component_node";
|
||||||
|
import { batched, Callback } from "./utils";
|
||||||
|
|
||||||
// Allows to get the target of a Reactive (used for making a new Reactive from the underlying object)
|
// Allows to get the target of a Reactive (used for making a new Reactive from the underlying object)
|
||||||
const TARGET = Symbol("Target");
|
const TARGET = Symbol("Target");
|
||||||
@@ -8,7 +9,6 @@ const KEYCHANGES = Symbol("Key changes");
|
|||||||
|
|
||||||
type ObjectKey = string | number | symbol;
|
type ObjectKey = string | number | symbol;
|
||||||
type Target = object;
|
type Target = object;
|
||||||
type Callback = () => void;
|
|
||||||
export type Reactive<T extends Target = Target> = T & {
|
export type Reactive<T extends Target = Target> = T & {
|
||||||
[TARGET]: any;
|
[TARGET]: any;
|
||||||
};
|
};
|
||||||
@@ -191,30 +191,6 @@ export function reactive<T extends Target>(target: T, callback: Callback = () =>
|
|||||||
return reactivesForTarget.get(callback) as Reactive<T>;
|
return reactivesForTarget.get(callback) as Reactive<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a batched version of a callback so that all calls to it in the same
|
|
||||||
* microtick will only call the original callback once.
|
|
||||||
*
|
|
||||||
* @param callback the callback to batch
|
|
||||||
* @returns a batched version of the original callback
|
|
||||||
*/
|
|
||||||
export function batched(callback: Callback): Callback {
|
|
||||||
let called = false;
|
|
||||||
return async () => {
|
|
||||||
// This await blocks all calls to the callback here, then releases them sequentially
|
|
||||||
// in the next microtick. This line decides the granularity of the batch.
|
|
||||||
await Promise.resolve();
|
|
||||||
if (!called) {
|
|
||||||
called = true;
|
|
||||||
callback();
|
|
||||||
// wait for all calls in this microtick to fall through before resetting "called"
|
|
||||||
// so that only the first call to the batched function calls the original callback
|
|
||||||
await Promise.resolve();
|
|
||||||
called = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const batchedRenderFunctions = new WeakMap<ComponentNode, Callback>();
|
const batchedRenderFunctions = new WeakMap<ComponentNode, Callback>();
|
||||||
/**
|
/**
|
||||||
* Creates a reactive object that will be observed by the current component.
|
* Creates a reactive object that will be observed by the current component.
|
||||||
|
|||||||
@@ -1,3 +1,29 @@
|
|||||||
|
export type Callback = () => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a batched version of a callback so that all calls to it in the same
|
||||||
|
* microtick will only call the original callback once.
|
||||||
|
*
|
||||||
|
* @param callback the callback to batch
|
||||||
|
* @returns a batched version of the original callback
|
||||||
|
*/
|
||||||
|
export function batched(callback: Callback): Callback {
|
||||||
|
let called = false;
|
||||||
|
return async () => {
|
||||||
|
// This await blocks all calls to the callback here, then releases them sequentially
|
||||||
|
// in the next microtick. This line decides the granularity of the batch.
|
||||||
|
await Promise.resolve();
|
||||||
|
if (!called) {
|
||||||
|
called = true;
|
||||||
|
callback();
|
||||||
|
// wait for all calls in this microtick to fall through before resetting "called"
|
||||||
|
// so that only the first call to the batched function calls the original callback
|
||||||
|
await Promise.resolve();
|
||||||
|
called = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export class EventBus extends EventTarget {
|
export class EventBus extends EventTarget {
|
||||||
trigger(name: string, payload?: any) {
|
trigger(name: string, payload?: any) {
|
||||||
this.dispatchEvent(new CustomEvent(name, { detail: payload }));
|
this.dispatchEvent(new CustomEvent(name, { detail: payload }));
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
xml,
|
xml,
|
||||||
} from "../src";
|
} from "../src";
|
||||||
import { batched, reactive } from "../src/reactivity";
|
import { reactive } from "../src/reactivity";
|
||||||
|
import { batched } from "../src/utils";
|
||||||
import {
|
import {
|
||||||
makeDeferred,
|
makeDeferred,
|
||||||
makeTestFixture,
|
makeTestFixture,
|
||||||
|
|||||||
+19
-1
@@ -1,4 +1,5 @@
|
|||||||
import { EventBus } from "../src/utils";
|
import { batched, EventBus } from "../src/utils";
|
||||||
|
import { nextMicroTick } from "./helpers";
|
||||||
|
|
||||||
describe("event bus behaviour", () => {
|
describe("event bus behaviour", () => {
|
||||||
test("can subscribe and be notified", () => {
|
test("can subscribe and be notified", () => {
|
||||||
@@ -33,3 +34,20 @@ describe("event bus behaviour", () => {
|
|||||||
bus.trigger("event", "hello world");
|
bus.trigger("event", "hello world");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("batched", () => {
|
||||||
|
test("callback is called only once after operations", async () => {
|
||||||
|
let n = 0;
|
||||||
|
let fn = batched(() => n++);
|
||||||
|
|
||||||
|
expect(n).toBe(0);
|
||||||
|
fn();
|
||||||
|
fn();
|
||||||
|
expect(n).toBe(0);
|
||||||
|
|
||||||
|
await nextMicroTick();
|
||||||
|
expect(n).toBe(1);
|
||||||
|
await nextMicroTick();
|
||||||
|
expect(n).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user