- commit
- 09eba9f
- parent
- cfcc818
- author
- Eric Bower
- date
- 2023-12-12 02:44:39 +0000 UTC
docs: readme
1 files changed,
+87,
-15
+87,
-15
1@@ -32,13 +32,13 @@ Read my introductory blog post:
2 # example: thunks are tasks for business logic
3
4 Thunks are the foundational central processing units. They have access to all
5-the actions being dispatched from thew view -- or other thunks. They also wield
6-the full power of structured concurrency.
7+the actions being dispatched from the view as well as your global state. They
8+also wield the full power of structured concurrency.
9
10 Every thunk that is created requires a unique id -- user provided string. This
11 provides us with a handful of benefits:
12
13-- User hand-labels each task created (intention)
14+- User hand-labels each thunk created
15 - Better tracability (via labels)
16 - Easier to debug async and side-effects in general (via labels)
17 - Build abstractions off naming conventions (e.g. creating routers
18@@ -51,25 +51,22 @@ thunks and endpoints.
19 Each run of a thunk gets its own `ctx` object which provides a substrate to
20 communicate between middleware.
21
22-You didn't know you wanted express middleware for the front-end, but let me get
23-you excited, it's powerful.
24-
25 ```ts
26-import { createThunks, mdw, call } from "starfx";
27+import { call, createThunks, mdw } from "starfx";
28
29 const thunks = createThunks();
30 // catch errors from task and logs them with extra info
31 thunks.use(mdw.err);
32 // where all the thunks get called in the middleware stack
33 thunks.use(thunks.routes());
34-thunks.use(function*(ctx, next) {
35+thunks.use(function* (ctx, next) {
36 console.log("last mdw in the stack");
37 yield* next();
38 });
39
40 // create a thunk
41 const log = thunks.create("log", function* (ctx, next) {
42- const resp = yield* call(fetch("https"//bower.sh"));;
43+ const resp = yield* call(fetch("https://bower.sh"));
44 const data = yield* call(resp.json());
45 console.log("before calling next middleware");
46 yield* next();
47@@ -97,7 +94,7 @@ api.use(api.routes());
48 // calls `window.fetch` with `ctx.request` and sets to `ctx.response`
49 api.use(mdw.fetch({ baseUrl: "https://jsonplaceholder.typicode.com" }));
50
51-// automatically cache results in datastore
52+// automatically cache Response json in datastore as-is
53 export const fetchUsers = api.get("/users", api.cache());
54
55 store.dispatch(fetchUsers());
56@@ -170,7 +167,7 @@ function App() {
57 <div>
58 {users.map((u) => <div key={u.id}>{u.name}</div>)}
59 <div>
60- <button onClick={api.trigger()}>fetch users</button>
61+ <button onClick={() => api.trigger()}>fetch users</button>
62 {api.isLoading ? <div>Loading ...</div> : null}
63 </div>
64 </div>
65@@ -184,9 +181,9 @@ Please see [examples repo](https://github.com/neurosnap/starfx-examples).
66
67 # when to use this library?
68
69-This primary target for this library are single-page apps (SPAs). This is for an
70-app that might live inside an object store or as a simple web server that serves
71-files and that's it.
72+The primary target for this library are single-page apps (SPAs). This is for an
73+app that might be hosted inside an object store (like s3) or with a simple web
74+server that serves files and that's it.
75
76 Is your app highly interactive, requiring it to persist data across pages? This
77 is the sweet spot for `starfx`.
78@@ -199,7 +196,7 @@ cannot claim it'll work well.
79
80 # what is structured concurrency?
81
82-This is a board term so I'll make this specific to how `starfx` works.
83+This is a broadd term so I'll make this specific to how `starfx` works.
84
85 Under-the-hood, thunks and endpoints are registered under the root task. Every
86 thunk and endpoint has their own supervisor that manages them. As a result, what
87@@ -223,6 +220,81 @@ In review:
88 - Supervisor tasks are designed to monitor task health (and automatically
89 recover in many cases)
90
91+# what is a supervisor task?
92+
93+A supervisor task is a way to monitor children tasks and probably most
94+importantly, manage their health. By structuring your side-effects and business
95+logic around supervisor tasks, we gain very interesting coding paradigms that
96+result is easier to read and manage code.
97+
98+The most basic version of a supervisor is simply an infinite loop that calls a
99+child task:
100+
101+```ts
102+function* supervisor() {
103+ while (true) {
104+ try {
105+ yield* call(someTask);
106+ } catch (err) {
107+ console.error(err);
108+ }
109+ }
110+}
111+```
112+
113+Here we call some task that should always be in a running and in a healthy
114+state. If it raises an exception, we log it and try to run the task again.
115+
116+All thunks and endpoints do is listen for particular actions being emitted onto
117+the `ActionContext`, which is just an event emitter.
118+
119+```ts
120+import { parallel, run, takeEvery } from "starfx";
121+
122+function* watchFetch() {
123+ const task = yield* takeEvery("FETCH_USERS", function* (action) {
124+ console.log(action);
125+ });
126+ yield* task;
127+}
128+
129+function* send() {
130+ yield* put({ type: "FETCH_USERS" });
131+ yield* put({ type: "FETCH_USERS" });
132+ yield* put({ type: "FETCH_USERS" });
133+}
134+
135+await run(
136+ parallel([watchFetch, send]),
137+);
138+```
139+
140+Here we create a supervisor function using a helper `takeEvery` to call a
141+function for every `FETCH_USERS` event emitted.
142+
143+However, this means that we are going to make the same request 3 times, we need
144+a throttle or debounce to prevent this issue.
145+
146+```ts
147+import { parallel, run, takeLeading } from "starfx";
148+
149+function* watchFetch() {
150+ const task = yield* takeLeading("FETCH_USERS", function* (action) {
151+ console.log(action);
152+ });
153+ yield* task;
154+}
155+```
156+
157+That's better, now only one task can be alive at one time.
158+
159+Both thunks and endpoints support overriding the default `takeEvery` supervisor
160+for either our officially supported supervisors `takeLatest` and `takeLeading`
161+or even a custom one!
162+
163+That's it. We are just leveraging the same tiny API that we are already using in
164+`starfx`.
165+
166 # talk
167
168 I recently gave a talk about deliminited continuations where I also discuss this