### Installing better-all using package managers Source: https://github.com/shuding/better-all/blob/main/README.md Provides commands for installing the 'better-all' library using popular JavaScript package managers like npm, pnpm, bun, and yarn. This ensures users can easily integrate the library into their projects. ```bash npm install better-all # or pnpm add better-all # or bun add better-all # or yarn add better-all ``` -------------------------------- ### Development Commands Source: https://github.com/shuding/better-all/blob/main/README.md Provides essential commands for developing the better-all project, including installing dependencies, running tests, and building the project. ```bash pnpm install # Install dependencies pnpm test # Run tests pnpm build # Build ``` -------------------------------- ### Demonstrating inefficient Promise.all for dependent tasks (TypeScript) Source: https://github.com/shuding/better-all/blob/main/README.md Illustrates the common but inefficient pattern of using Promise.all when tasks have sequential dependencies, leading to longer execution times. This example highlights how sequential execution can be suboptimal. ```typescript // Common pattern: Sequential execution wastes time const [a, b] = await Promise.all([getA(), getB()]) // a: 1s, b: 10s → takes 10s const c = await getC(a) // c: 10s → takes 10s // Total: 20 seconds ``` ```typescript const a = await getA() // a: 1s -> takes 1s const [b, c] = await Promise.all([ // b: 10s, c: 10s -> takes 10s getB(), getC(a) ]) // Total: 11 seconds ``` ```typescript const a = await getA() // a: 10s -> takes 10s const [b, c] = await Promise.all([ // b: 10s, c: 1s -> takes 10s getB(), getC(a) ]) // Total: 20 seconds // Naive approach: const [a, b] = await Promise.all([getA(), getB()]) // a: 10s, b: 10s → takes 10s const c = await getC(a) // c: 1s → takes 1s // Total: 11 seconds ``` ```typescript const [[a, c], b] = await Promise.all([ getA().then(a => getC(a).then(c => [a, c])), getB() ]) ``` -------------------------------- ### Using better-all for optimized Promise.all execution (TypeScript) Source: https://github.com/shuding/better-all/blob/main/README.md Demonstrates the core functionality of the 'better-all' library, showing how to define asynchronous tasks with dependencies and achieve optimal parallelization automatically. This example uses the object-based API for clarity. ```typescript import { all } from 'better-all' const { a, b, c } = await all({ async a() { return getA() }, // 1s async b() { return getB() }, // 10s async c() { return getC(await this.$.a) } // 10s (waits for a) }) // Total: 11 seconds - optimal parallelization! ``` -------------------------------- ### Execute Tasks with Dependencies using 'all' (TypeScript) Source: https://github.com/shuding/better-all/blob/main/README.md Illustrates how to define task dependencies using the 'all' function. A task can access the results of other tasks via `this.$`. This example shows fetching user data first, then fetching profile and settings in parallel using the user's ID. ```typescript const { user, profile, settings } = await all({ async user() { return fetchUser(1) }, async profile() { return fetchProfile((await this.$.user).id) }, async settings() { return fetchSettings((await this.$.user).id) } }) // User runs first, then profile and settings run in parallel ``` -------------------------------- ### Complex Dependency Graph with 'all' (TypeScript) Source: https://github.com/shuding/better-all/blob/main/README.md Demonstrates a complex dependency graph where tasks have multiple dependencies. The 'all' function ensures optimal parallelization by running tasks as soon as their dependencies are met. This example shows a graph where 'a' and 'b' run in parallel, 'c' depends on 'a', 'd' depends on 'b', and 'e' depends on both 'c' and 'd'. ```typescript const { a, b, c, d, e } = await all({ async a() { return 1 }, async b() { return 2 }, async c() { return (await this.$.a) + 10 }, async d() { return (await this.$.b) + 20 }, async e() { return (await this.$.c) + (await this.$.d) } }) // a and b run in parallel // c waits for a, d waits for b (c and d can overlap) // e waits for both c and d // { a: 1, b: 2, c: 11, d: 22, e: 33 } console.log({ a, b, c, d, e }) ``` -------------------------------- ### Handling Dependency Failures with `allSettled()` in TypeScript Source: https://github.com/shuding/better-all/blob/main/README.md Shows how to handle dependency failures when using `allSettled()`. If a task depends on a failed task, it will also fail unless the error is explicitly caught within the task. This example demonstrates a task that succeeds by catching the error from a dependent failed task. ```typescript const result = await allSettled({ async a() { throw new Error('a failed') }, async b() { // This will fail because 'a' failed const aValue = await this.$.a return aValue + 10 }, async c() { // This handles the error and succeeds try { const aValue = await this.$.a return aValue + 10 } catch (err) { return 'fallback value' } } }) // result.a: { status: 'rejected', reason: Error('a failed') } // result.b: { status: 'rejected', reason: Error('a failed') } // result.c: { status: 'fulfilled', value: 'fallback value' } ``` -------------------------------- ### External Abort Signal with All Tasks Source: https://github.com/shuding/better-all/blob/main/README.md Shows how to integrate an external AbortController with `all()`. This allows parent processes or other logic to signal cancellation to all tasks managed by `all()`, ensuring coordinated termination. ```typescript const controller = new AbortController() const result = await all({ async a() { return fetchData(this.$signal) }, async b() { return fetchMoreData(this.$signal) } }, { signal: controller.signal }) ``` -------------------------------- ### Stepped Dependency Chain with Optimal Parallelization using 'all' (TypeScript) Source: https://github.com/shuding/better-all/blob/main/README.md Explains how the 'all' function achieves optimal parallelization even with stepped dependency chains. Tasks like `postsWithAuthor` might appear sequential in their internal logic (e.g., awaiting `user` then `posts`), but `all` initiates all tasks concurrently, ensuring that underlying operations like fetching posts can run while other tasks are being processed. ```typescript const result = await all({ async user() { return fetchUser(1) }, async posts() { return fetchPosts((await this.$.user).id) }, async postsWithAuthor() { const user = await this.$.user console.log(`Fetched user: ${user.name}`) const posts = await this.$.posts return posts.map(post => ({ ...post, author: user.name })) }, }) // This still gives optimal parallelization. ``` -------------------------------- ### Abort Signal in All Tasks Source: https://github.com/shuding/better-all/blob/main/README.md Demonstrates how to use the built-in AbortSignal within tasks executed by `all()`. If one task fails, its AbortSignal is aborted, which can then be used to cancel other sibling tasks, preventing resource waste. ```typescript const result = await all({ async fetchUser() { const res = await fetch('/api/user', { signal: this.$signal }) return res.json() }, async fetchPosts() { // If fetchUser fails, this.$signal will be aborted const res = await fetch('/api/posts', { signal: this.$signal }) return res.json() } }) ``` -------------------------------- ### all(tasks, options?) Source: https://github.com/shuding/better-all/blob/main/README.md Executes a set of asynchronous tasks with automatic dependency resolution, ensuring maximal parallelization. It returns a promise that resolves to an object containing all task results. ```APIDOC ## `all(tasks, options?)` ### Description Execute tasks with automatic dependency resolution. This function ensures maximal parallelization by running independent tasks concurrently and waiting only for necessary dependencies. ### Method `all` ### Parameters #### `tasks` (Object) - Required An object where keys are task names and values are asynchronous functions representing the tasks. #### `options` (Object) - Optional Configuration options for the `all` function. - `debug` (boolean): If set to `true`, outputs a waterfall chart visualizing task execution timeline. - `signal` (AbortSignal): An `AbortSignal` that can be used to abort all running tasks externally. ### Task Function Signature Each task function within the `tasks` object receives the following arguments: - `this.$` (Object): An object containing promises for all other task results. This allows tasks to express dependencies on each other (e.g., `await this.$.dependencyName`). - `this.$signal` (AbortSignal): An `AbortSignal` that automatically aborts if any sibling task fails. This is crucial for preventing resource leaks and unnecessary computations. ### Returns - A `Promise` that resolves to an object with the results of all tasks, keyed by their respective task names. - The promise rejects if any of the tasks fail, similar to the behavior of `Promise.all`. ### Request Example ```javascript import { all } from 'better-all'; const results = await all({ async taskA() { return 1; }, async taskB() { return 2; }, async taskC() { return await this.$.taskA + await this.$.taskB; } }); // results will be { taskA: 1, taskB: 2, taskC: 3 } ``` ### Response #### Success Response (200) - `results` (Object): An object containing the resolved values of all tasks. - `taskName` (any): The resolved value of the task named `taskName`. #### Response Example ```json { "taskA": 1, "taskB": 2, "taskC": 3 } ``` ``` -------------------------------- ### Execute Tasks with Dependency Resolution using 'all' (TypeScript) Source: https://github.com/shuding/better-all/blob/main/README.md Demonstrates basic parallel execution of asynchronous tasks using the 'all' function. Tasks are defined as an object of async functions and run concurrently. The results are returned as an object with keys corresponding to the task names. ```typescript const { a, b, c } = await all({ async a() { await sleep(1000); return 1 }, async b() { await sleep(1000); return 2 }, async c() { await sleep(1000); return 3 } }) // All three run in parallel // Returns { a: 1, b: 2, c: 3 } ``` -------------------------------- ### allSettled(tasks, options?) Source: https://github.com/shuding/better-all/blob/main/README.md Executes a set of asynchronous tasks with automatic dependency resolution, similar to `all`, but returns settled results for all tasks, indicating whether each task was fulfilled or rejected. ```APIDOC ## `allSettled(tasks, options?)` ### Description Execute tasks with automatic dependency resolution, returning settled results for all tasks. This function behaves like `Promise.allSettled`, ensuring that all tasks are executed to completion (or failure) and their outcomes are reported. ### Method `allSettled` ### Parameters #### `tasks` (Object) - Required An object where keys are task names and values are asynchronous functions representing the tasks. #### `options` (Object) - Optional Configuration options for the `allSettled` function. - `debug` (boolean): If set to `true`, outputs a waterfall chart visualizing task execution timeline. - `signal` (AbortSignal): An `AbortSignal` that can be used to abort all running tasks externally. ### Task Function Signature Each task function within the `tasks` object receives the following arguments: - `this.$` (Object): An object containing promises for all other task results. This allows tasks to express dependencies on each other (e.g., `await this.$.dependencyName`). - `this.$signal` (AbortSignal): An `AbortSignal` that is only affected by an external `AbortSignal` passed in the `options`. It does *not* abort when a sibling task fails. ### Returns - A `Promise` that resolves to an object with the settled results of all tasks. Each result will be in the format `{ status: 'fulfilled', value }` or `{ status: 'rejected', reason }`. - This function never rejects, even if individual tasks fail. Failed tasks are reported within the results object. - If a task depends on a failed task, the dependent task will also fail unless it includes error handling (e.g., a try-catch block) within its own execution. ### Request Example ```javascript import { allSettled } from 'better-all'; const results = await allSettled({ async taskA() { return 1; }, async taskB() { throw new Error('Task B failed'); }, async taskC() { return await this.$.taskA + 5; } }); // results will be: // { // taskA: { status: 'fulfilled', value: 1 }, // taskB: { status: 'rejected', reason: Error('Task B failed') }, // taskC: { status: 'fulfilled', value: 6 } // } ``` ### Response #### Success Response (200) - `results` (Object): An object containing the settled results of all tasks. - `taskName` ({ status: 'fulfilled', value: any } | { status: 'rejected', reason: any }): The settled result of the task named `taskName`. ``` -------------------------------- ### Racing Operations with Flow Source: https://github.com/shuding/better-all/blob/main/README.md Demonstrates using `flow()` for racing operations. Multiple tasks attempt to fetch data from different sources, and the first one to call `this.$end()` with its result determines the overall outcome, optimizing for speed. ```typescript const result = await flow({ async fetchFromPrimary() { await sleep(100) const data = await fetch('/api/primary') this.$end(await data.json()) }, async fetchFromBackup() { await sleep(500) const data = await fetch('/api/backup') this.$end(await data.json()) } }) ``` -------------------------------- ### Using allSettled with better-all (TypeScript) Source: https://github.com/shuding/better-all/blob/main/README.md Illustrates the usage of the `allSettled` function from the 'better-all' library, which executes tasks with dependency resolution but returns settled results for all tasks, similar to `Promise.allSettled`. This is useful when you need to know the outcome of every task, regardless of success or failure. ```typescript import { allSettled } from 'better-all' const results = await allSettled({ async task1() { /* ... */ }, async task2() { /* ... */ }, async task3() { /* depends on task1 */ await this.$.task1 } }) ``` -------------------------------- ### Enable Debug Mode with `all()` in TypeScript Source: https://github.com/shuding/better-all/blob/main/README.md Enables debug mode for the `all()` function to visualize task execution with an ASCII waterfall chart. This chart displays task timelines, durations, dependencies, and parallel vs. sequential execution. It helps in identifying performance bottlenecks and understanding task relationships. ```typescript const result = await all({ async config() { await sleep(50) return { apiUrl: 'https://api.example.com' } }, async user() { await sleep(120) return { id: 1, name: 'Alice' } }, async posts() { const user = await this.$.user await sleep(200) return fetchPosts(user.id) }, async profile() { const user = await this.$.user const config = await this.$.config await sleep(80) return fetchProfile(user.id, config.apiUrl) }, async analytics() { const posts = await this.$.posts const profile = await this.$.profile await sleep(40) return computeAnalytics(posts, profile) } }, { debug: true }) ``` -------------------------------- ### TypeScript Type Inference for Task Results with Better All Source: https://context7.com/shuding/better-all/llms.txt Demonstrates automatic type inference for task results and dependencies using Better All's `all` function. It shows how `this.$` correctly types task results as promises and infers complex object types based on task definitions. ```typescript import { all, allSettled, flow } from 'better-all' // Automatic type inference for task results const result = await all({ async num() { return 42 }, async str() { return 'hello' }, async combined() { const n = await this.$.num // n: number (auto-inferred!) const s = await this.$.str // s: string (auto-inferred!) return `${s}: ${n}` } }) result.num // type: number result.str // type: string result.combined // type: string // Complex object types with dependencies const result = await all({ user() { return { id: 1, name: 'Alice' } }, async profile() { const user = await this.$.user // user: { id: number; name: string } return { userId: user.id, displayName: user.name.toUpperCase() } } }) result.user // type: { id: number; name: string } result.profile // type: { userId: number; displayName: string } // allSettled result types const result = await allSettled({ num() { return 42 }, str() { return 'hello' } }) // result.num: { status: 'fulfilled'; value: number } | { status: 'rejected'; reason: any } if (result.num.status === 'fulfilled') { console.log(result.num.value) // value: number } // flow requires explicit type parameter const f = await flow({ async task1() { this.$end(42) // number return 1 }, async task2() { this.$end('hello') // string return 'world' } }) // f: number | string | undefined ``` -------------------------------- ### Execute Tasks with Dependency Resolution using `all()` in TypeScript Source: https://context7.com/shuding/better-all/llms.txt The `all()` function executes async tasks in parallel while automatically resolving dependencies. Tasks access other task results via `this.$.taskName`. If any task fails, the promise rejects and `this.$signal` is aborted to allow cleanup of other running tasks. It supports basic parallel execution, tasks with dependencies, complex dependency graphs, and abort signals for resource cleanup. Debug mode can be enabled to visualize task execution timelines. ```typescript import { all } from 'better-all' // Basic parallel execution - all tasks run simultaneously const { a, b, c } = await all({ async a() { return 1 }, async b() { return 2 }, async c() { return 3 } }) // Result: { a: 1, b: 2, c: 3 } // With dependencies - c waits for a, while b runs in parallel const result = await all({ async user() { return { id: 1, name: 'Alice' } }, async posts() { const user = await this.$.user // Waits for user task return [{ id: 1, userId: user.id, title: 'Post 1' }] }, async settings() { return { theme: 'dark' } // Runs in parallel with user } }) // user and settings run in parallel, posts waits for user // Complex dependency graph with optimal parallelization const { a, b, c, d, e } = await all({ async a() { return 1 }, async b() { return 2 }, async c() { return (await this.$.a) + 10 }, // Depends on a async d() { return (await this.$.b) + 20 }, // Depends on b async e() { return (await this.$.c) + (await this.$.d) } // Depends on c and d }) // a and b run in parallel // c waits for a, d waits for b (c and d can overlap) // e waits for both c and d // Result: { a: 1, b: 2, c: 11, d: 22, e: 33 } // With abort signal for resource cleanup const controller = new AbortController() const result = await all({ async fetchUser() { const res = await fetch('/api/user', { signal: this.$signal }) return res.json() }, async fetchPosts() { // If fetchUser fails, this.$signal will be aborted const res = await fetch('/api/posts', { signal: this.$signal }) return res.json() } }, { signal: controller.signal }) // Debug mode - outputs waterfall chart const result = await all({ async config() { await new Promise(r => setTimeout(r, 50)) return { apiUrl: 'https://api.example.com' } }, async user() { await new Promise(r => setTimeout(r, 120)) return { id: 1, name: 'Alice' } }, async posts() { const user = await this.$.user await new Promise(r => setTimeout(r, 200)) return [{ userId: user.id, title: 'Post' }] } }, { debug: true }) // Outputs: // ╔════════════════════════════════════════════════════════════════════════════════╗ // ║ Task Execution Waterfall ║ // ╠════════════════════════════════════════════════════════════════════════════════╣ // ║ Total Duration: 320.54ms ║ // ╚════════════════════════════════════════════════════════════════════════════════╝ // Task │ Deps │ Duration │ Timeline // ───────┼──────┼──────────┼────────────────────────────────────────────────── // config │ - │ 51.4ms │ ████████ // user │ - │ 121.4ms │ ████████████████████ // posts │ user │ 322.6ms │ ░░░░░░░░░░░░░░░░░░░░██████████████████████████████ // Legend: █ = active (fulfilled), ▓ = active (rejected), ░ = waiting on dependency ``` -------------------------------- ### Conditional Early Exit with Flow Source: https://github.com/shuding/better-all/blob/main/README.md Shows how `flow()` can be used for conditional early exits. The `validateInput` task checks input validity and calls `this.$end()` with an error object if invalid, preventing further processing. ```typescript const result = await flow<{ error: string } | ProcessedData>({ async validateInput() { const isValid = await validate(input) if (!isValid) this.$end({ error: 'Invalid input' }) return input }, async processData() { const validInput = await this.$.validateInput const processed = await heavyComputation(validInput) this.$end({ success: true, data: processed }) } }) ``` -------------------------------- ### Early Exit from Cache with Flow Source: https://github.com/shuding/better-all/blob/main/README.md Illustrates using `flow()` to exit early when cached data is found. The `checkCache` task uses `this.$end(cached)` to immediately return cached data, skipping subsequent API fetching and processing tasks. ```typescript import { flow } from 'better-all' const data = await flow({ async checkCache() { const cached = await getFromCache('key') if (cached) this.$end(cached) // Exit early with cached data return null }, async fetchFromApi() { const user = await this.$.checkCache // Will throw if cache hit return await fetchExpensiveData() }, async processData() { const apiData = await this.$.fetchFromApi this.$end(transform(apiData)) } }) ``` -------------------------------- ### Error Propagation with `all()` in TypeScript Source: https://github.com/shuding/better-all/blob/main/README.md Demonstrates how errors propagate to dependent tasks when using the `all()` function, similar to `Promise.all`. If a task fails, subsequent tasks depending on it will also be affected, and the `try...catch` block will capture the initial error. ```typescript try { await all({ async a() { throw new Error('Failed') }, async b() { return (await this.$.a) + 1 } }) } catch (err) { console.error(err) // Error: Failed } ``` -------------------------------- ### flow(tasks, options?) Source: https://github.com/shuding/better-all/blob/main/README.md Executes a collection of asynchronous tasks, automatically resolving dependencies between them and providing support for early exit. The return type `R` is determined by the `$end()` function's argument type. ```APIDOC ## flow(tasks, options?) ### Description Executes tasks with automatic dependency resolution and early exit support. ### Method `flow` (function) ### Parameters #### Type Parameters - **``**: **Required**. Specifies the return type that `$end()` must accept. #### Arguments - **`tasks`**: Object of async task functions. Each function receives `this.$` (promises for all task results), `this.$signal` (AbortSignal), and `this.$end(value: R)` (function to exit early). - **`options`**: Optional configuration object, same as used in the `all()` function. ### Returns - A promise that resolves to `R | undefined`. It resolves with the value passed to the first `$end()` call, or `undefined` if `$end()` is never called. ### See Also - [Early Exit Flow](#early-exit-flow) ### Request Example ```typescript // Example demonstrating basic parallel execution const { a, b, c } = await flow({ async a() { await sleep(1000); return 1 }, async b() { await sleep(1000); return 2 }, async c() { await sleep(1000); return 3 } }); // Example with dependencies const { user, profile, settings } = await flow({ async user() { return fetchUser(1) }, async profile() { return fetchProfile((await this.$.user).id) }, async settings() { return fetchSettings((await this.$.user).id) } }); // Example demonstrating type safety const result = await flow({ async num() { return 42 }, async str() { return 'hello' }, async combined() { const n = await this.$.num // n: number (auto-inferred!) const s = await this.$.str // s: string (auto-inferred!) return `${s}: ${n}` } }); // Example with a complex dependency graph const { a, b, c, d, e } = await flow({ async a() { return 1 }, async b() { return 2 }, async c() { return (await this.$.a) + 10 }, async d() { return (await this.$.b) + 20 }, async e() { return (await this.$.c) + (await this.$.d) } }); // Example of a stepped dependency chain with optimal parallelization const result = await flow({ async user() { return fetchUser(1) }, async posts() { return fetchPosts((await this.$.user).id) }, async postsWithAuthor() { const user = await this.$.user console.log(`Fetched user: ${user.name}`) const posts = await this.$.posts return posts.map(post => ({ ...post, author: user.name })) }, }); ``` ### Response Example ```json { "a": 1, "b": 2, "c": 3 } ``` ### Error Handling - If a task throws an error, the entire flow will reject with that error. - If `$end()` is called multiple times, only the first call's value is used. ``` -------------------------------- ### Type-Safe Task Execution with 'all' (TypeScript) Source: https://github.com/shuding/better-all/blob/main/README.md Highlights the full TypeScript support and automatic type inference provided by the 'all' function. Task results are strongly typed, and intermediate results accessed via `this.$` are also correctly inferred, ensuring type safety throughout the execution. ```typescript const result = await all({ async num() { return 42 }, async str() { return 'hello' }, async combined() { const n = await this.$.num // n: number (auto-inferred!) const s = await this.$.str // s: string (auto-inferred!) return `${s}: ${n}` } }) result.num // number result.str // string result.combined // string ``` -------------------------------- ### Flow Return Type Specification Source: https://github.com/shuding/better-all/blob/main/README.md Illustrates specifying the return type for `flow()` using a type parameter. This ensures type safety for values passed to `this.$end()` and the final return value of the flow. ```typescript const result = await flow({ async task1() { this.$end(42) // number return 1 }, async task2() { this.$end('hello') // string return 'world' } }) ``` -------------------------------- ### Using `allSettled()` for Task Results in TypeScript Source: https://github.com/shuding/better-all/blob/main/README.md Illustrates the use of `allSettled()` to ensure all tasks complete and return their settled state (fulfilled or rejected). This function never rejects itself, providing detailed results for each task, including values or reasons for failure. ```typescript const result = await allSettled({ async a() { return 1 }, async b() { throw new Error('Task b failed') }, async c() { return 3 } }) // result.a: { status: 'fulfilled', value: 1 } // result.b: { status: 'rejected', reason: Error('Task b failed') } // result.c: { status: 'fulfilled', value: 3 } if (result.a.status === 'fulfilled') { console.log(result.a.value) // 1 } if (result.b.status === 'rejected') { console.error(result.b.reason) // Error: Task b failed } ``` -------------------------------- ### allSettled - Execute Tasks Without Throwing on Failure (TypeScript) Source: https://context7.com/shuding/better-all/llms.txt The `allSettled()` function executes multiple asynchronous tasks and returns an object containing the settlement status and result (value or reason) for each task. It is useful for handling partial failures gracefully, as it does not throw an error when a task fails. Dependencies on failed tasks will also result in errors, but tasks can implement error handling to provide fallback values. ```typescript import { allSettled } from 'better-all' // Mixed success and failure results const result = await allSettled({ async a() { return 1 }, async b() { throw new Error('Task b failed') }, async c() { return 3 } }) // Result: // { // a: { status: 'fulfilled', value: 1 }, // b: { status: 'rejected', reason: Error('Task b failed') }, // c: { status: 'fulfilled', value: 3 } // } // Handling dependency on failed task const result = await allSettled({ async a() { throw new Error('a failed') }, async b() { // This will also fail because 'a' failed const aValue = await this.$.a return aValue + 10 }, async c() { // This handles the error and succeeds try { const aValue = await this.$.a return aValue + 10 } catch (err) { return 'fallback value' } } }) // Result: // { // a: { status: 'rejected', reason: Error('a failed') }, // b: { status: 'rejected', reason: Error('a failed') }, // c: { status: 'fulfilled', value: 'fallback value' } // } // Partial API failure handling const result = await allSettled({ async user() { return { id: 1, name: 'User' } }, async posts() { const user = await this.$.user throw new Error('Posts API failed') }, async settings() { return { theme: 'dark' } } }) if (result.user.status === 'fulfilled') { console.log('User:', result.user.value) } if (result.posts.status === 'rejected') { console.error('Posts failed:', result.posts.reason.message) } if (result.settings.status === 'fulfilled') { console.log('Settings:', result.settings.value) } ``` -------------------------------- ### Flow Explicit Undefined Return Type Source: https://github.com/shuding/better-all/blob/main/README.md Demonstrates explicitly allowing `undefined` as a return value for `flow()` by including it in the type parameter. This is necessary if a task might call `this.$end(undefined)`. ```typescript // Explicitly allow undefined const result = await flow({ async task1() { const data = await getData() if (!data) this.$end(undefined) // ✅ OK: undefined is in the type parameter this.$end(data) } }) ``` -------------------------------- ### flow - Execute Tasks with Early Exit Support (TypeScript) Source: https://context7.com/shuding/better-all/llms.txt The `flow()` function enables early exit patterns where any task can terminate the entire flow by calling `this.$end(value)`. This is useful for cache checks, racing operations, or conditional computations. The first task to call `$end()` determines the return value. Tasks that attempt to access dependencies after `$end()` has been called will receive errors, which are caught silently. The type parameter `` is required and specifies the type that `$end()` accepts. ```typescript import { flow } from 'better-all' // Early exit from cache check const data = await flow({ async checkCache() { const cached = await getFromCache('user-key') if (cached) this.$end(cached) // Exit early with cached data return null }, async fetchFromApi() { const cache = await this.$.checkCache // Will throw if cache hit const response = await fetch('/api/user') return response.json() }, async processData() { const apiData = await this.$.fetchFromApi this.$end(transform(apiData)) } }) // Racing operations - first response wins const result = await flow({ async fetchFromPrimary() { await new Promise(r => setTimeout(r, 100)) const data = await fetch('/api/primary') this.$end(await data.json()) }, async fetchFromBackup() { await new Promise(r => setTimeout(r, 500)) const data = await fetch('/api/backup') this.$end(await data.json()) } }) // Returns data from whichever endpoint responds first // Conditional early exit with validation const result = await flow<{ error: string } | ProcessedData>({ async validateInput() { const isValid = await validate(input) if (!isValid) this.$end({ error: 'Invalid input' }) return input }, async processData() { const validInput = await this.$.validateInput const processed = await heavyComputation(validInput) this.$end({ success: true, data: processed }) } }) // No task calls $end() - returns undefined const result = await flow({ async task1() { return 1 }, async task2() { return 2 } }) // result is undefined // With external abort signal const controller = new AbortController() const result = await flow({ async task1() { if (this.$signal.aborted) throw this.$signal.reason await new Promise(r => setTimeout(r, 100)) if (this.$signal.aborted) throw this.$signal.reason this.$end('done') } }, { signal: controller.signal }) // Abort after timeout setTimeout(() => controller.abort(new Error('Timeout')), 50) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.