- commit
- 7a40ffe
- parent
- bf9eaa4
- author
- Eric Bower
- date
- 2024-08-26 03:02:57 +0000 UTC
chore: doc comments
5 files changed,
+87,
-0
+52,
-0
1@@ -8,6 +8,58 @@ export interface ParallelRet<T> extends Computation<Result<T>[]> {
2 immediate: Channel<Result<T>, void>;
3 }
4
5+/**
6+ * The goal of `parallel` is to make it easier to cooridnate multiple async
7+ * operations in parallel, with different ways to receive completed tasks.
8+ *
9+ * All tasks are called with {@link fx.safe} which means they will never
10+ * throw an exception. Instead all tasks will return a Result object that
11+ * the end development must evaluate in order to grab the value.
12+ *
13+ * @example
14+ * ```ts
15+ * import { parallel } from "starfx";
16+ *
17+ * function* run() {
18+ * const task = yield* parallel([job1, job2]);
19+ * // wait for all tasks to complete before moving to next yield point
20+ * const results = yield* task;
21+ * // job1 = results[0];
22+ * // job2 = results[1];
23+ * }
24+ * ```
25+ *
26+ * Instead of waiting for all tasks to complete, we can instead loop over
27+ * tasks as they arrive:
28+ *
29+ * @example
30+ * ```ts
31+ * function* run() {
32+ * const task = yield* parallel([job1, job2]);
33+ * for (const job of yield* each(task.immediate)) {
34+ * // job2 completes first then it will be first in list
35+ * console.log(job);
36+ * yield* each.next();
37+ * }
38+ * }
39+ * ```
40+ *
41+ * Or we can instead loop over tasks in order of the array provided to
42+ * parallel:
43+ *
44+ * @example
45+ * ```ts
46+ * function* run() {
47+ * const task = yield* parallel([job1, job2]);
48+ * for (const job of yield* each(task.sequence)) {
49+ * // job1 then job2 will be returned regardless of when the jobs
50+ * // complete
51+ * console.log(job);
52+ * yield* each.next();
53+ * }
54+ * }
55+ * ```
56+ */
57 export function parallel<T>(operations: Callable<T>[]) {
58 const sequence = createChannel<Result<T>>();
59 const immediate = createChannel<Result<T>>();
+18,
-0
1@@ -1,6 +1,24 @@
2 import type { Callable, Operation, Result } from "../deps.ts";
3 import { call, Err, Ok } from "../deps.ts";
4
5+/**
6+ * The goal of `safe` is to wrap Operations to prevent them from raising
7+ * and error. The result of `safe` is always a {@link Result} type.
8+ *
9+ * @example
10+ * ```ts
11+ * import { safe } from "starfx";
12+ *
13+ * function* run() {
14+ * const results = yield* safe(fetch("api.com"));
15+ * if (result.ok) {
16+ * console.log(result.value);
17+ * } else {
18+ * console.error(result.error);
19+ * }
20+ * }
21+ * ```
22+ */
23 export function* safe<T>(operator: Callable<T>): Operation<Result<T>> {
24 try {
25 const value = yield* call<T>(operator as any);
+4,
-0
1@@ -46,6 +46,10 @@ export function supervise<T>(
2 };
3 }
4
5+/**
6+ * keepAlive accepts a list of operations and calls them all with
7+ * {@link supervise}
8+ */
9 export function* keepAlive(
10 ops: Callable<unknown>[],
11 backoff?: (attempt: number) => number,
+4,
-0
1@@ -195,6 +195,10 @@ export function* payload<CurCtx extends FetchJsonCtx = FetchJsonCtx>(
2 yield* next();
3 }
4
5+/*
6+ * This middleware simply checks if `ctx.response` already contains a
7+ * truthy value, and if it does, bail out of the middleware stack.
8+ */
9 export function response<CurCtx extends FetchCtx = FetchCtx>(
10 response?: Response,
11 ) {
+9,
-0
1@@ -26,6 +26,15 @@ export interface ApiMdwProps<
2 * the {@link createApi}.
3 *
4 * It is not required, however, it is battle-tested and highly recommended.
5+ *
6+ * List of mdw:
7+ * - {@link mdw.err}
8+ * - {@link mdw.actions}
9+ * - {@link mdw.queryCtx}
10+ * - {@link mdw.customKey}
11+ * - {@link mdw.nameParser}
12+ * - {@link mdw.loaderApi}
13+ * - {@link mdw.cache}
14 */
15 export function api<Ctx extends ApiCtx = ApiCtx, S extends AnyState = AnyState>(
16 props: ApiMdwProps<Ctx, S>,