- commit
- 4842df8
- parent
- 0ba8393
- author
- Eric Bower
- date
- 2023-09-18 01:06:19 +0000 UTC
refactor(redux): take strat Trying to think about performance considerations with implementation
4 files changed,
+56,
-56
M
deps.ts
+1,
-0
1@@ -3,6 +3,7 @@ export type {
2 Instruction,
3 Operation,
4 Port,
5+ Predicate,
6 Result,
7 Scope,
8 Signal,
+20,
-9
1@@ -1,42 +1,53 @@
2 import type { AnyAction } from "./types.ts";
3+import type { Predicate } from "./deps.ts";
4
5 type ActionType = string;
6 type GuardPredicate<G extends T, T = unknown> = (arg: T) => arg is G;
7-type Predicate = (action: AnyAction) => boolean;
8+type APredicate = (action: AnyAction) => boolean;
9 type StringableActionCreator<A extends AnyAction = AnyAction> = {
10 (...args: unknown[]): A;
11 toString(): string;
12 };
13-type SubPattern = Predicate | StringableActionCreator | ActionType;
14+type SubPattern = APredicate | StringableActionCreator | ActionType;
15 export type Pattern = SubPattern | SubPattern[];
16 type ActionSubPattern<Guard extends AnyAction = AnyAction> =
17 | GuardPredicate<Guard, AnyAction>
18 | StringableActionCreator<Guard>
19- | Predicate
20+ | APredicate
21 | ActionType;
22 export type ActionPattern<Guard extends AnyAction = AnyAction> =
23 | ActionSubPattern<Guard>
24 | ActionSubPattern<Guard>[];
25
26-export function matcher(pattern: ActionPattern): (input: AnyAction) => boolean {
27+export function matcher(pattern: ActionPattern): Predicate<AnyAction> {
28 if (pattern === "*") {
29- return (input: AnyAction) => !!input;
30+ return function* (input) {
31+ return !!input;
32+ };
33 }
34
35 if (typeof pattern === "string") {
36- return (input: AnyAction) => pattern === input.type;
37+ return function* (input) {
38+ return pattern === input.type;
39+ };
40 }
41
42 if (Array.isArray(pattern)) {
43- return (input: AnyAction) => pattern.some((p) => matcher(p)(input));
44+ return function* (input) {
45+ return pattern.some((p) => matcher(p)(input));
46+ };
47 }
48
49 if (typeof pattern === "function" && Object.hasOwn(pattern, "toString")) {
50- return (input: AnyAction) => pattern.toString() === input.type;
51+ return function* (input) {
52+ return pattern.toString() === input.type;
53+ };
54 }
55
56 if (typeof pattern === "function") {
57- return (input: AnyAction) => pattern(input) as boolean;
58+ return function* (input) {
59+ return pattern(input) as boolean;
60+ };
61 }
62
63 throw new Error("invalid pattern");
+33,
-41
1@@ -1,5 +1,5 @@
2 import type { Action, Operation, Signal } from "../deps.ts";
3-import { createContext, each, spawn } from "../deps.ts";
4+import { createContext, each, filter, spawn } from "../deps.ts";
5 import { call } from "../fx/mod.ts";
6 import { ActionPattern, matcher } from "../matcher.ts";
7 import type { ActionWPayload, AnyAction } from "../types.ts";
8@@ -11,6 +11,15 @@ export const ActionContext = createContext<Signal<Action, void>>(
9 );
10 export const StoreContext = createContext<StoreLike>("redux:store");
11
12+export function* put(action: AnyAction | AnyAction[]) {
13+ const store = yield* StoreContext;
14+ if (Array.isArray(action)) {
15+ action.map((act) => store.dispatch(act));
16+ } else {
17+ store.dispatch(action);
18+ }
19+}
20+
21 export function emit({
22 signal,
23 action,
24@@ -28,35 +37,26 @@ export function emit({
25 }
26 }
27
28-export function* once({
29- signal,
30- pattern,
31-}: {
32- signal: Signal<Action, void>;
33- pattern: ActionPattern;
34-}) {
35- for (const action of yield* each(signal.stream)) {
36- const match = matcher(pattern);
37- if (match(action)) {
38- return action;
39- }
40- yield* each.next;
41- }
42-}
43-
44 export function* select<S, R>(selectorFn: (s: S) => R) {
45 const store = yield* StoreContext;
46 return selectorFn(store.getState() as S);
47 }
48
49+function* createPatternStream(pattern: ActionPattern) {
50+ const signal = yield* ActionContext;
51+ const match = matcher(pattern);
52+ const fd = filter(match)(signal.stream);
53+ return fd;
54+}
55+
56 export function take<P>(pattern: ActionPattern): Operation<ActionWPayload<P>>;
57 export function* take(pattern: ActionPattern): Operation<Action> {
58- const signal = yield* ActionContext;
59- const action = yield* once({
60- signal,
61- pattern,
62- });
63- return action as Action;
64+ const fd = yield* createPatternStream(pattern);
65+ for (const action of yield* each(fd)) {
66+ return action;
67+ }
68+
69+ return { type: "take failed, this should not be possible" };
70 }
71
72 export function* takeEvery<T>(
73@@ -64,10 +64,10 @@ export function* takeEvery<T>(
74 op: (action: Action) => Operation<T>,
75 ) {
76 return yield* spawn(function* (): Operation<void> {
77- while (true) {
78- const action = yield* take(pattern);
79- if (!action) continue;
80+ const fd = yield* createPatternStream(pattern);
81+ for (const action of yield* each(fd)) {
82 yield* spawn(() => op(action));
83+ yield* each.next;
84 }
85 });
86 }
87@@ -77,14 +77,15 @@ export function* takeLatest<T>(
88 op: (action: Action) => Operation<T>,
89 ) {
90 return yield* spawn(function* (): Operation<void> {
91+ const fd = yield* createPatternStream(pattern);
92 let lastTask;
93- while (true) {
94- const action = yield* take(pattern);
95+
96+ for (const action of yield* each(fd)) {
97 if (lastTask) {
98 yield* lastTask.halt();
99 }
100- if (!action) continue;
101 lastTask = yield* spawn(() => op(action));
102+ yield* each.next;
103 }
104 });
105 }
106@@ -95,20 +96,11 @@ export function* takeLeading<T>(
107 op: (action: Action) => Operation<T>,
108 ) {
109 return yield* spawn(function* (): Operation<void> {
110- while (true) {
111- const action = yield* take(pattern);
112- if (!action) continue;
113+ const fd = yield* createPatternStream(pattern);
114+ for (const action of yield* each(fd)) {
115 yield* call(() => op(action));
116+ yield* each.next;
117 }
118 });
119 }
120 export const leading = takeLeading;
121-
122-export function* put(action: AnyAction | AnyAction[]) {
123- const store = yield* StoreContext;
124- if (Array.isArray(action)) {
125- action.map((act) => store.dispatch(act));
126- } else {
127- store.dispatch(action);
128- }
129-}
+2,
-6
1@@ -58,14 +58,10 @@ export function* put(action: AnyAction | AnyAction[]) {
2 }
3
4 export function* useActions(pattern: ActionPattern): Stream<AnyAction, void> {
5- const match = matcher(pattern);
6 const { output } = yield* ActionContext;
7- // deno-lint-ignore require-yield
8- function* fn(a: AnyAction) {
9- return match(a);
10- }
11+ const match = matcher(pattern);
12 // return a subscription to the filtered actions.
13- const result = yield* filter(fn)(output);
14+ const result = yield* filter(match)(output);
15 return result;
16 }
17