-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathduration.ts
More file actions
62 lines (51 loc) · 1.76 KB
/
duration.ts
File metadata and controls
62 lines (51 loc) · 1.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import { NodeRuntime } from "@effect/platform-node";
import { Effect, Duration, Ref, Fiber, Console } from "effect";
import { type DurationInput } from "effect/Duration";
type DebounceOptions = {
mode: "leading" | "trailing";
};
const debounce = <A extends any[], O>(
fn: (...args: A) => Effect.Effect<O>,
duration: DurationInput,
options: DebounceOptions = { mode: "trailing" }
) => {
const fiberRef = Ref.unsafeMake<Fiber.RuntimeFiber<O> | null>(null);
const lastCallTime = Ref.unsafeMake<Duration.Duration>(Duration.zero);
return (...args: A) => {
return Effect.gen(function* () {
const now = Duration.millis(Date.now());
const prevCallTime = yield* Ref.get(lastCallTime);
yield* Ref.set(lastCallTime, now);
const timeSinceLastCall = Duration.subtract(now, prevCallTime);
const shouldCallNow =
options.mode === "leading" &&
Duration.greaterThan(timeSinceLastCall, duration);
const prevFiber = yield* Ref.get(fiberRef);
if (prevFiber !== null) {
yield* Fiber.interrupt(prevFiber);
}
if (shouldCallNow) {
yield* fn(...args);
} else {
const newFiber = yield* Effect.fork(
Effect.sleep(duration).pipe(
Effect.andThen(() => fn(...args)),
Effect.onInterrupt(() => Console.log("interrupted"))
)
);
yield* Ref.set(fiberRef, newFiber);
yield* Fiber.join(newFiber);
}
});
};
};
const testFn = (a: number, b: number) => {
return Effect.gen(function* () {
yield* Console.log("testFn", a, b);
});
};
const main = Effect.gen(function* () {
yield* debounce(testFn, Duration.millis(1000), { mode: "leading" })(1, 2);
yield* debounce(testFn, "1 second")(1, 2);
});
main.pipe(NodeRuntime.runMain);