yield-result 0.1.5 β 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -18
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -65,30 +65,24 @@ npm install yield-result
|
|
|
65
65
|
|
|
66
66
|
---
|
|
67
67
|
|
|
68
|
-
##
|
|
68
|
+
## π¬ Architectural Analysis & V8 Engine Optimization
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
### Why We Do Not Use `throw` Internally for Flow Control
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
While libraries like `neverthrow` are fantastic, their generator-based flow control (`safeTry`) relies on calling `.safeUnwrap()`, which **throws native exceptions internally** to unwind the generator stack back to a `catch` block.
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
In JavaScript V8 engines (Node.js, Chrome), throwing exceptions forces the engine to:
|
|
75
|
+
1. Pause the execution loop.
|
|
76
|
+
2. Capture full call stack frames.
|
|
77
|
+
3. Deoptimize JIT compiler loops.
|
|
75
78
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
| **`yield-result` (`safe.sync`)** | **`207,485 ops/sec`** | β‘ **3.55x FASTER than native try/catch** |
|
|
79
|
-
| **Native `try/catch` with `throw`** | **`58,515 ops/sec`** | π’ 3.55x slower |
|
|
79
|
+
**`yield-result` takes a zero-exception approach**:
|
|
80
|
+
Our generator runners (`safe.sync` / `safe.async` / `Result.gen`) rely **exclusively on ECMAScript native iteration protocols (`Symbol.iterator`)**.
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
- **`Ok<T>`** returns its value directly in 0 suspension steps.
|
|
83
|
+
- **`Err<E>`** yields the `Err` object once to the runner, which immediately triggers `gen.return()` and early-returns the `Err` value.
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
| Implementation | Operations / sec | Average Latency |
|
|
87
|
-
| :--- | :---: | :---: |
|
|
88
|
-
| **Native `try/catch` (no throw)** | `11,372,962 ops/sec` | `0.0001 ms` |
|
|
89
|
-
| **`yield-result` (`safe.sync`)** | `231,068 ops/sec` | `0.0043 ms` |
|
|
90
|
-
|
|
91
|
-
*Over 230,000 complete domain pipelines evaluated per second on a single threadβzero impact on network or database latencies.*
|
|
85
|
+
By avoiding internal `throw` statements entirely, `yield-result` keeps your execution pipeline 100% JIT-optimizable by the V8 engine under both happy and unhappy path conditions.
|
|
92
86
|
|
|
93
87
|
---
|
|
94
88
|
|
|
@@ -261,6 +255,46 @@ export async function handleOrderCheckout(orderId: string) {
|
|
|
261
255
|
|
|
262
256
|
---
|
|
263
257
|
|
|
258
|
+
## π¦ Guidelines & Anti-Patterns: Async/Await + Generator Boundaries
|
|
259
|
+
|
|
260
|
+
Combining `async/await` with generator delegation (`yield* await asyncFn()`) is a powerful pattern, but mixing two control-flow models requires adhering to key architectural guidelines to avoid performance pitfalls and concurrency bottlenecks.
|
|
261
|
+
|
|
262
|
+
### π΄ Anti-Pattern 1: Sequential Request Waterfalls
|
|
263
|
+
|
|
264
|
+
Avoid unwrapping multiple independent async calls sequentially inside `safe.async`:
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
// β ANTI-PATTERN: Creates a sequential waterfall latency bottleneck!
|
|
268
|
+
const user = yield* await fetchUser(id); // Waits 100ms
|
|
269
|
+
const config = yield* await fetchConfig(id); // Waits 100ms (Total: 200ms)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**β
Recommended Pattern (Parallel Concurrency):**
|
|
273
|
+
Execute independent Promises concurrently with `Promise.all` before unwrapping:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
// β
RECOMMENDED: Concurrently fetches in parallel (Total: 100ms)
|
|
277
|
+
const [userRes, configRes] = await Promise.all([fetchUser(id), fetchConfig(id)]);
|
|
278
|
+
const user = yield* userRes;
|
|
279
|
+
const config = yield* configRes;
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
### π΄ Anti-Pattern 2: Missing `await` on Async Result Promises
|
|
285
|
+
|
|
286
|
+
Forgetting `await` before yielding an async function that returns `Promise<Result<T, E>>`:
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
// β ANTI-PATTERN: Forgetting 'await' on Promise<Result>
|
|
290
|
+
const user = yield* fetchUserAsync(id); // Error: Trying to iterate over a Promise object!
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**β
Recommended Pattern:**
|
|
294
|
+
Always use `yield* await fetchUserAsync(id)` when calling functions that return a `Promise<Result<T, E>>`.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
264
298
|
## π‘οΈ Built-in Safety Features
|
|
265
299
|
|
|
266
300
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yield-result",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Rust-style ? operator for TypeScript using generators (yield*). Zero dependencies, type-safe error handling.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -47,9 +47,8 @@
|
|
|
47
47
|
],
|
|
48
48
|
"license": "MIT",
|
|
49
49
|
"devDependencies": {
|
|
50
|
+
"neverthrow": "^8.2.0",
|
|
50
51
|
"typescript": "^5.5.4",
|
|
51
52
|
"vitest": "^2.0.5"
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
-
|