@aicgen/aicgen 1.0.0 → 1.0.2
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/AGENTS.md +7 -2
- package/claude.md +1 -1
- package/dist/index.js +6272 -5503
- package/package.json +1 -1
- package/.agent/rules/api-design.md +0 -649
- package/.agent/rules/architecture.md +0 -2507
- package/.agent/rules/best-practices.md +0 -622
- package/.agent/rules/code-style.md +0 -308
- package/.agent/rules/design-patterns.md +0 -577
- package/.agent/rules/devops.md +0 -230
- package/.agent/rules/error-handling.md +0 -417
- package/.agent/rules/instructions.md +0 -28
- package/.agent/rules/language.md +0 -786
- package/.agent/rules/performance.md +0 -710
- package/.agent/rules/security.md +0 -587
- package/.agent/rules/testing.md +0 -572
- package/.agent/workflows/add-documentation.md +0 -10
- package/.agent/workflows/generate-integration-tests.md +0 -10
- package/.agent/workflows/generate-unit-tests.md +0 -11
- package/.agent/workflows/performance-audit.md +0 -11
- package/.agent/workflows/refactor-extract-module.md +0 -12
- package/.agent/workflows/security-audit.md +0 -12
- package/.gemini/instructions.md +0 -4843
|
@@ -1,710 +0,0 @@
|
|
|
1
|
-
# Performance Rules
|
|
2
|
-
|
|
3
|
-
# Performance Basics
|
|
4
|
-
|
|
5
|
-
## Choose the Right Data Structure
|
|
6
|
-
|
|
7
|
-
Different data structures have different speeds for different operations.
|
|
8
|
-
|
|
9
|
-
### Arrays vs Objects vs Maps
|
|
10
|
-
|
|
11
|
-
```pseudocode
|
|
12
|
-
// ❌ Slow: Looking up in array (O(n))
|
|
13
|
-
users = [
|
|
14
|
-
{ id: 1, name: 'Alice' },
|
|
15
|
-
{ id: 2, name: 'Bob' },
|
|
16
|
-
// ... 1000 more
|
|
17
|
-
]
|
|
18
|
-
user = users.find(u => u.id == 500) // Checks 500 items
|
|
19
|
-
|
|
20
|
-
// ✅ Fast: Looking up in Map (O(1))
|
|
21
|
-
users = Map()
|
|
22
|
-
users.set(1, { id: 1, name: 'Alice' })
|
|
23
|
-
users.set(2, { id: 2, name: 'Bob' })
|
|
24
|
-
|
|
25
|
-
user = users.get(500) // Instant lookup
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### Arrays vs Sets
|
|
29
|
-
|
|
30
|
-
```pseudocode
|
|
31
|
-
// ❌ Slow: Checking if item exists in array
|
|
32
|
-
items = [1, 2, 3, 4, 5, ... 1000 more]
|
|
33
|
-
if items.contains(500): // Checks every item
|
|
34
|
-
|
|
35
|
-
// ✅ Fast: Checking if item exists in Set
|
|
36
|
-
items = Set([1, 2, 3, 4, 5, ... 1000 more])
|
|
37
|
-
if items.has(500): // Instant check
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### When to Use Each
|
|
41
|
-
|
|
42
|
-
| Data Structure | Good For |
|
|
43
|
-
|----------------|----------|
|
|
44
|
-
| **Array/List** | Ordered items, iteration |
|
|
45
|
-
| **Object/Dict** | Key-value pairs (string keys) |
|
|
46
|
-
| **Map** | Key-value pairs (any type keys), frequent lookups |
|
|
47
|
-
| **Set** | Unique values, membership checks |
|
|
48
|
-
|
|
49
|
-
## Avoid N+1 Queries
|
|
50
|
-
|
|
51
|
-
One of the most common performance problems.
|
|
52
|
-
|
|
53
|
-
```pseudocode
|
|
54
|
-
// ❌ BAD: N+1 queries (1 + N database calls)
|
|
55
|
-
orders = database.query("SELECT * FROM orders")
|
|
56
|
-
|
|
57
|
-
for each order in orders:
|
|
58
|
-
// Separate query for EACH order! 😱
|
|
59
|
-
customer = database.query(
|
|
60
|
-
"SELECT * FROM customers WHERE id = ?",
|
|
61
|
-
[order.customer_id]
|
|
62
|
-
)
|
|
63
|
-
order.customer = customer
|
|
64
|
-
// If 100 orders = 101 database calls!
|
|
65
|
-
|
|
66
|
-
// ✅ GOOD: Single query with JOIN
|
|
67
|
-
ordersWithCustomers = database.query("
|
|
68
|
-
SELECT
|
|
69
|
-
orders.*,
|
|
70
|
-
customers.name as customer_name,
|
|
71
|
-
customers.email as customer_email
|
|
72
|
-
FROM orders
|
|
73
|
-
JOIN customers ON orders.customer_id = customers.id
|
|
74
|
-
")
|
|
75
|
-
// Only 1 database call!
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## Don't Load What You Don't Need
|
|
79
|
-
|
|
80
|
-
```pseudocode
|
|
81
|
-
// ❌ Bad: Fetching entire object when you only need one field
|
|
82
|
-
user = database.query("SELECT * FROM users WHERE id = ?", [id])
|
|
83
|
-
print(user.email)
|
|
84
|
-
|
|
85
|
-
// ✅ Good: Fetch only what you need
|
|
86
|
-
result = database.query(
|
|
87
|
-
"SELECT email FROM users WHERE id = ?",
|
|
88
|
-
[id]
|
|
89
|
-
)
|
|
90
|
-
print(result.email)
|
|
91
|
-
|
|
92
|
-
// ❌ Bad: Loading all records
|
|
93
|
-
users = database.query("SELECT * FROM users")
|
|
94
|
-
|
|
95
|
-
// ✅ Good: Add LIMIT
|
|
96
|
-
users = database.query("SELECT * FROM users LIMIT 100")
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Use Async for I/O Operations
|
|
100
|
-
|
|
101
|
-
Don't block the program waiting for slow operations.
|
|
102
|
-
|
|
103
|
-
```pseudocode
|
|
104
|
-
// ❌ Slow: Blocking operations (synchronous)
|
|
105
|
-
file1 = readFileSync("file1.txt")
|
|
106
|
-
file2 = readFileSync("file2.txt")
|
|
107
|
-
file3 = readFileSync("file3.txt")
|
|
108
|
-
// Total: 300ms (100ms each, one after another)
|
|
109
|
-
|
|
110
|
-
// ✅ Fast: Async operations (parallel)
|
|
111
|
-
files = await Promise.all([
|
|
112
|
-
readFile("file1.txt"),
|
|
113
|
-
readFile("file2.txt"),
|
|
114
|
-
readFile("file3.txt")
|
|
115
|
-
])
|
|
116
|
-
// Total: 100ms (all at once)
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Avoid Unnecessary Work in Loops
|
|
120
|
-
|
|
121
|
-
```pseudocode
|
|
122
|
-
// ❌ Bad: Work done every iteration
|
|
123
|
-
for i in 0 to items.length:
|
|
124
|
-
total = calculateTotal(items) // Recalculated each time!
|
|
125
|
-
if items[i].price > total * 0.1:
|
|
126
|
-
// ...
|
|
127
|
-
|
|
128
|
-
// ✅ Good: Work done once
|
|
129
|
-
total = calculateTotal(items)
|
|
130
|
-
for i in 0 to items.length:
|
|
131
|
-
if items[i].price > total * 0.1:
|
|
132
|
-
// ...
|
|
133
|
-
|
|
134
|
-
// ❌ Bad: Array length calculated each time
|
|
135
|
-
for i in 0 to items.length:
|
|
136
|
-
// ...
|
|
137
|
-
|
|
138
|
-
// ✅ Good: Length cached (minor improvement)
|
|
139
|
-
len = items.length
|
|
140
|
-
for i in 0 to len:
|
|
141
|
-
// ...
|
|
142
|
-
|
|
143
|
-
// ✅ Best: Modern for-each loop
|
|
144
|
-
for each item in items:
|
|
145
|
-
// ...
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## Index Your Database
|
|
149
|
-
|
|
150
|
-
Indexes make lookups fast, but slow down writes.
|
|
151
|
-
|
|
152
|
-
```sql
|
|
153
|
-
-- Without index: Checks every row
|
|
154
|
-
SELECT * FROM users WHERE email = 'alice@example.com';
|
|
155
|
-
-- With 1 million users: ~1 second
|
|
156
|
-
|
|
157
|
-
-- Add index
|
|
158
|
-
CREATE INDEX idx_users_email ON users(email);
|
|
159
|
-
|
|
160
|
-
-- Now same query is instant
|
|
161
|
-
SELECT * FROM users WHERE email = 'alice@example.com';
|
|
162
|
-
-- With 1 million users: ~1 millisecond
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### When to Add Indexes
|
|
166
|
-
|
|
167
|
-
- Columns used in WHERE clauses
|
|
168
|
-
- Columns used in JOIN conditions
|
|
169
|
-
- Columns used in ORDER BY
|
|
170
|
-
|
|
171
|
-
```sql
|
|
172
|
-
-- Frequently queried
|
|
173
|
-
CREATE INDEX idx_orders_status ON orders(status);
|
|
174
|
-
CREATE INDEX idx_users_email ON users(email);
|
|
175
|
-
|
|
176
|
-
-- Used in joins
|
|
177
|
-
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## Cache Expensive Results
|
|
181
|
-
|
|
182
|
-
Don't recalculate the same thing repeatedly.
|
|
183
|
-
|
|
184
|
-
```pseudocode
|
|
185
|
-
// ❌ Bad: Calculating every time
|
|
186
|
-
function getReport(userId):
|
|
187
|
-
data = expensiveCalculation(userId) // 5 seconds
|
|
188
|
-
return data
|
|
189
|
-
|
|
190
|
-
// Called 100 times = 500 seconds!
|
|
191
|
-
|
|
192
|
-
// ✅ Good: Cache results
|
|
193
|
-
cache = Map()
|
|
194
|
-
|
|
195
|
-
function getReport(userId):
|
|
196
|
-
if cache.has(userId):
|
|
197
|
-
return cache.get(userId) // Instant
|
|
198
|
-
|
|
199
|
-
data = expensiveCalculation(userId)
|
|
200
|
-
cache.set(userId, data)
|
|
201
|
-
return data
|
|
202
|
-
|
|
203
|
-
// First call: 5 seconds, next 99 calls: instant
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
## Batch Operations
|
|
207
|
-
|
|
208
|
-
Process multiple items together instead of one at a time.
|
|
209
|
-
|
|
210
|
-
```pseudocode
|
|
211
|
-
// ❌ Bad: Individual database calls
|
|
212
|
-
for each user in users:
|
|
213
|
-
database.execute("INSERT INTO users (name) VALUES (?)", [user.name])
|
|
214
|
-
// 100 users = 100 database calls
|
|
215
|
-
|
|
216
|
-
// ✅ Good: Batch insert
|
|
217
|
-
database.execute("
|
|
218
|
-
INSERT INTO users (name)
|
|
219
|
-
VALUES " + users.map(u => "(?)").join(", "),
|
|
220
|
-
users.map(u => u.name)
|
|
221
|
-
)
|
|
222
|
-
// 100 users = 1 database call
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
## Profile Before Optimizing
|
|
226
|
-
|
|
227
|
-
Don't guess where the problem is - measure!
|
|
228
|
-
|
|
229
|
-
```pseudocode
|
|
230
|
-
// Measure execution time
|
|
231
|
-
startTime = currentTime()
|
|
232
|
-
result = await slowOperation()
|
|
233
|
-
endTime = currentTime()
|
|
234
|
-
print("Operation took:", endTime - startTime, "ms")
|
|
235
|
-
|
|
236
|
-
// Measure specific parts
|
|
237
|
-
startDB = currentTime()
|
|
238
|
-
data = await database.query("...")
|
|
239
|
-
print("Database:", currentTime() - startDB, "ms")
|
|
240
|
-
|
|
241
|
-
startProcess = currentTime()
|
|
242
|
-
processed = processData(data)
|
|
243
|
-
print("Processing:", currentTime() - startProcess, "ms")
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
## Common Performance Mistakes
|
|
247
|
-
|
|
248
|
-
### Mistake 1: Nested Loops with Database Queries
|
|
249
|
-
|
|
250
|
-
```pseudocode
|
|
251
|
-
// ❌ TERRIBLE: Nested queries
|
|
252
|
-
for each user in users:
|
|
253
|
-
for each order in orders:
|
|
254
|
-
product = await database.query(
|
|
255
|
-
"SELECT * FROM products WHERE id = ?",
|
|
256
|
-
[order.product_id]
|
|
257
|
-
)
|
|
258
|
-
// 100 users × 50 orders = 5000 database calls!
|
|
259
|
-
|
|
260
|
-
// ✅ GOOD: Load all data first
|
|
261
|
-
products = await database.query("SELECT * FROM products")
|
|
262
|
-
productMap = Map()
|
|
263
|
-
for each p in products:
|
|
264
|
-
productMap.set(p.id, p)
|
|
265
|
-
|
|
266
|
-
for each user in users:
|
|
267
|
-
for each order in orders:
|
|
268
|
-
product = productMap.get(order.product_id) // Instant
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### Mistake 2: Loading Everything into Memory
|
|
272
|
-
|
|
273
|
-
```pseudocode
|
|
274
|
-
// ❌ Bad: Loading 1 million records
|
|
275
|
-
allUsers = await database.query("SELECT * FROM users")
|
|
276
|
-
// Crashes with out of memory!
|
|
277
|
-
|
|
278
|
-
// ✅ Good: Process in batches
|
|
279
|
-
BATCH_SIZE = 1000
|
|
280
|
-
offset = 0
|
|
281
|
-
|
|
282
|
-
while true:
|
|
283
|
-
users = await database.query(
|
|
284
|
-
"SELECT * FROM users LIMIT ? OFFSET ?",
|
|
285
|
-
[BATCH_SIZE, offset]
|
|
286
|
-
)
|
|
287
|
-
|
|
288
|
-
if users.length == 0:
|
|
289
|
-
break
|
|
290
|
-
|
|
291
|
-
await processUsers(users)
|
|
292
|
-
offset = offset + BATCH_SIZE
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### Mistake 3: Not Using Indexes
|
|
296
|
-
|
|
297
|
-
```sql
|
|
298
|
-
-- ❌ Slow: No index on email column
|
|
299
|
-
SELECT * FROM users WHERE email = 'alice@example.com';
|
|
300
|
-
-- 1 million rows: ~2 seconds
|
|
301
|
-
|
|
302
|
-
-- ✅ Fast: Add index
|
|
303
|
-
CREATE INDEX idx_users_email ON users(email);
|
|
304
|
-
-- Same query: ~2 milliseconds
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
## Quick Performance Checklist
|
|
308
|
-
|
|
309
|
-
- [ ] Use Map/Set for lookups instead of Array
|
|
310
|
-
- [ ] Avoid N+1 queries (use JOINs)
|
|
311
|
-
- [ ] Add database indexes on frequently queried columns
|
|
312
|
-
- [ ] Don't load all records (use LIMIT)
|
|
313
|
-
- [ ] Cache expensive calculations
|
|
314
|
-
- [ ] Run independent operations in parallel
|
|
315
|
-
- [ ] Move work outside of loops
|
|
316
|
-
- [ ] Batch database operations
|
|
317
|
-
- [ ] Profile before optimizing
|
|
318
|
-
|
|
319
|
-
## When to Optimize
|
|
320
|
-
|
|
321
|
-
1. **Measure first** - Is there actually a problem?
|
|
322
|
-
2. **Find the bottleneck** - What's slow?
|
|
323
|
-
3. **Fix the biggest problem** - Don't waste time on small gains
|
|
324
|
-
4. **Measure again** - Did it help?
|
|
325
|
-
|
|
326
|
-
Don't optimize prematurely - write clear code first, optimize when needed!
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
---
|
|
330
|
-
|
|
331
|
-
# Caching Strategies
|
|
332
|
-
|
|
333
|
-
## In-Memory Caching
|
|
334
|
-
|
|
335
|
-
```typescript
|
|
336
|
-
class Cache<T> {
|
|
337
|
-
private cache = new Map<string, { value: T; expiry: number }>();
|
|
338
|
-
|
|
339
|
-
set(key: string, value: T, ttlMs: number = 60000): void {
|
|
340
|
-
this.cache.set(key, {
|
|
341
|
-
value,
|
|
342
|
-
expiry: Date.now() + ttlMs
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
get(key: string): T | null {
|
|
347
|
-
const item = this.cache.get(key);
|
|
348
|
-
if (!item) return null;
|
|
349
|
-
|
|
350
|
-
if (Date.now() > item.expiry) {
|
|
351
|
-
this.cache.delete(key);
|
|
352
|
-
return null;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
return item.value;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// Usage
|
|
360
|
-
const userCache = new Cache<User>();
|
|
361
|
-
|
|
362
|
-
async function getUser(id: string): Promise<User> {
|
|
363
|
-
const cached = userCache.get(id);
|
|
364
|
-
if (cached) return cached;
|
|
365
|
-
|
|
366
|
-
const user = await db.findUser(id);
|
|
367
|
-
userCache.set(id, user, 300000); // 5 minutes
|
|
368
|
-
return user;
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
## Redis Caching
|
|
373
|
-
|
|
374
|
-
```typescript
|
|
375
|
-
import Redis from 'ioredis';
|
|
376
|
-
|
|
377
|
-
const redis = new Redis();
|
|
378
|
-
|
|
379
|
-
async function getCachedUser(id: string): Promise<User | null> {
|
|
380
|
-
const cached = await redis.get(`user:${id}`);
|
|
381
|
-
if (cached) return JSON.parse(cached);
|
|
382
|
-
|
|
383
|
-
const user = await db.findUser(id);
|
|
384
|
-
await redis.setex(`user:${id}`, 300, JSON.stringify(user)); // 5 min TTL
|
|
385
|
-
return user;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// Cache invalidation on update
|
|
389
|
-
async function updateUser(id: string, data: Partial<User>) {
|
|
390
|
-
const user = await db.updateUser(id, data);
|
|
391
|
-
await redis.del(`user:${id}`); // Invalidate cache
|
|
392
|
-
return user;
|
|
393
|
-
}
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
## HTTP Caching
|
|
397
|
-
|
|
398
|
-
```typescript
|
|
399
|
-
// Cache-Control headers
|
|
400
|
-
app.get('/api/products', (req, res) => {
|
|
401
|
-
res.set('Cache-Control', 'public, max-age=300'); // 5 minutes
|
|
402
|
-
res.json(products);
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
// ETag for conditional requests
|
|
406
|
-
app.get('/api/user/:id', async (req, res) => {
|
|
407
|
-
const user = await getUser(req.params.id);
|
|
408
|
-
const etag = generateETag(user);
|
|
409
|
-
|
|
410
|
-
res.set('ETag', etag);
|
|
411
|
-
|
|
412
|
-
if (req.headers['if-none-match'] === etag) {
|
|
413
|
-
return res.status(304).end(); // Not Modified
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
res.json(user);
|
|
417
|
-
});
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
## Cache-Aside Pattern
|
|
421
|
-
|
|
422
|
-
```typescript
|
|
423
|
-
// Also called "lazy loading"
|
|
424
|
-
async function getProduct(id: string): Promise<Product> {
|
|
425
|
-
// 1. Check cache
|
|
426
|
-
const cached = await redis.get(`product:${id}`);
|
|
427
|
-
if (cached) return JSON.parse(cached);
|
|
428
|
-
|
|
429
|
-
// 2. Cache miss - load from database
|
|
430
|
-
const product = await db.findProduct(id);
|
|
431
|
-
|
|
432
|
-
// 3. Store in cache
|
|
433
|
-
await redis.setex(`product:${id}`, 600, JSON.stringify(product));
|
|
434
|
-
|
|
435
|
-
return product;
|
|
436
|
-
}
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
## Memoization
|
|
440
|
-
|
|
441
|
-
```typescript
|
|
442
|
-
const memoize = <T extends (...args: any[]) => any>(fn: T): T => {
|
|
443
|
-
const cache = new Map<string, ReturnType<T>>();
|
|
444
|
-
|
|
445
|
-
return ((...args: any[]) => {
|
|
446
|
-
const key = JSON.stringify(args);
|
|
447
|
-
if (cache.has(key)) return cache.get(key);
|
|
448
|
-
|
|
449
|
-
const result = fn(...args);
|
|
450
|
-
cache.set(key, result);
|
|
451
|
-
return result;
|
|
452
|
-
}) as T;
|
|
453
|
-
};
|
|
454
|
-
|
|
455
|
-
// Cache expensive computations
|
|
456
|
-
const calculateDiscount = memoize((price: number, tier: string) => {
|
|
457
|
-
// Complex calculation
|
|
458
|
-
return result;
|
|
459
|
-
});
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
## Cache Invalidation Strategies
|
|
463
|
-
|
|
464
|
-
```typescript
|
|
465
|
-
// Time-based expiry
|
|
466
|
-
await redis.setex(key, 300, value); // Expires after 5 minutes
|
|
467
|
-
|
|
468
|
-
// Event-based invalidation
|
|
469
|
-
async function updateProduct(id: string, data: ProductUpdate) {
|
|
470
|
-
await db.updateProduct(id, data);
|
|
471
|
-
await redis.del(`product:${id}`);
|
|
472
|
-
await redis.del('products:list'); // Invalidate list cache too
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Cache warming
|
|
476
|
-
async function warmCache() {
|
|
477
|
-
const popularProducts = await db.getMostViewed(100);
|
|
478
|
-
for (const product of popularProducts) {
|
|
479
|
-
await redis.setex(`product:${product.id}`, 3600, JSON.stringify(product));
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
---
|
|
486
|
-
|
|
487
|
-
# Async Performance Patterns
|
|
488
|
-
|
|
489
|
-
## Parallel Execution
|
|
490
|
-
|
|
491
|
-
```typescript
|
|
492
|
-
// ❌ Sequential - slow
|
|
493
|
-
async function getUserData(userId: string) {
|
|
494
|
-
const user = await fetchUser(userId); // 100ms
|
|
495
|
-
const posts = await fetchPosts(userId); // 150ms
|
|
496
|
-
const comments = await fetchComments(userId); // 120ms
|
|
497
|
-
return { user, posts, comments }; // Total: 370ms
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// ✅ Parallel - fast
|
|
501
|
-
async function getUserData(userId: string) {
|
|
502
|
-
const [user, posts, comments] = await Promise.all([
|
|
503
|
-
fetchUser(userId),
|
|
504
|
-
fetchPosts(userId),
|
|
505
|
-
fetchComments(userId)
|
|
506
|
-
]);
|
|
507
|
-
return { user, posts, comments }; // Total: 150ms
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
// ✅ Partial parallel with dependencies
|
|
511
|
-
async function getOrderDetails(orderId: string) {
|
|
512
|
-
const order = await fetchOrder(orderId); // Must fetch first
|
|
513
|
-
|
|
514
|
-
const [customer, items, shipping] = await Promise.all([
|
|
515
|
-
fetchCustomer(order.customerId),
|
|
516
|
-
fetchOrderItems(orderId),
|
|
517
|
-
fetchShippingInfo(orderId)
|
|
518
|
-
]);
|
|
519
|
-
|
|
520
|
-
return { order, customer, items, shipping };
|
|
521
|
-
}
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
## Promise.allSettled for Partial Failures
|
|
525
|
-
|
|
526
|
-
```typescript
|
|
527
|
-
// Return partial data instead of complete failure
|
|
528
|
-
async function getDashboard(userId: string) {
|
|
529
|
-
const [user, orders, stats] = await Promise.allSettled([
|
|
530
|
-
getUser(userId),
|
|
531
|
-
getOrders(userId),
|
|
532
|
-
getStats(userId)
|
|
533
|
-
]);
|
|
534
|
-
|
|
535
|
-
return {
|
|
536
|
-
user: user.status === 'fulfilled' ? user.value : null,
|
|
537
|
-
orders: orders.status === 'fulfilled' ? orders.value : [],
|
|
538
|
-
stats: stats.status === 'fulfilled' ? stats.value : null,
|
|
539
|
-
errors: {
|
|
540
|
-
user: user.status === 'rejected' ? user.reason.message : null,
|
|
541
|
-
orders: orders.status === 'rejected' ? orders.reason.message : null,
|
|
542
|
-
stats: stats.status === 'rejected' ? stats.reason.message : null
|
|
543
|
-
}
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
## Batch Processing
|
|
549
|
-
|
|
550
|
-
```typescript
|
|
551
|
-
// ❌ One at a time - slow
|
|
552
|
-
async function processUsers(userIds: string[]) {
|
|
553
|
-
for (const id of userIds) {
|
|
554
|
-
await updateUser(id);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// ✅ Batch processing
|
|
559
|
-
async function processUsers(userIds: string[]) {
|
|
560
|
-
const BATCH_SIZE = 50;
|
|
561
|
-
|
|
562
|
-
for (let i = 0; i < userIds.length; i += BATCH_SIZE) {
|
|
563
|
-
const batch = userIds.slice(i, i + BATCH_SIZE);
|
|
564
|
-
await Promise.all(batch.map(id => updateUser(id)));
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
// ✅ Bulk database operations
|
|
569
|
-
async function createUsers(users: User[]) {
|
|
570
|
-
await db.query(`
|
|
571
|
-
INSERT INTO users (name, email)
|
|
572
|
-
VALUES ${users.map(() => '(?, ?)').join(', ')}
|
|
573
|
-
`, users.flatMap(u => [u.name, u.email]));
|
|
574
|
-
}
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
## Debouncing and Throttling
|
|
578
|
-
|
|
579
|
-
```typescript
|
|
580
|
-
// Debounce: Wait until user stops typing
|
|
581
|
-
const debounce = <T extends (...args: any[]) => any>(
|
|
582
|
-
fn: T,
|
|
583
|
-
delay: number
|
|
584
|
-
): ((...args: Parameters<T>) => void) => {
|
|
585
|
-
let timeoutId: NodeJS.Timeout;
|
|
586
|
-
|
|
587
|
-
return (...args: Parameters<T>) => {
|
|
588
|
-
clearTimeout(timeoutId);
|
|
589
|
-
timeoutId = setTimeout(() => fn(...args), delay);
|
|
590
|
-
};
|
|
591
|
-
};
|
|
592
|
-
|
|
593
|
-
// Throttle: Execute at most once per interval
|
|
594
|
-
const throttle = <T extends (...args: any[]) => any>(
|
|
595
|
-
fn: T,
|
|
596
|
-
limit: number
|
|
597
|
-
): ((...args: Parameters<T>) => void) => {
|
|
598
|
-
let inThrottle: boolean;
|
|
599
|
-
|
|
600
|
-
return (...args: Parameters<T>) => {
|
|
601
|
-
if (!inThrottle) {
|
|
602
|
-
fn(...args);
|
|
603
|
-
inThrottle = true;
|
|
604
|
-
setTimeout(() => (inThrottle = false), limit);
|
|
605
|
-
}
|
|
606
|
-
};
|
|
607
|
-
};
|
|
608
|
-
|
|
609
|
-
// Usage
|
|
610
|
-
const searchUsers = debounce(query => api.search(query), 300);
|
|
611
|
-
const handleScroll = throttle(() => console.log('scroll'), 100);
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
## Rate Limiting Concurrent Operations
|
|
615
|
-
|
|
616
|
-
```typescript
|
|
617
|
-
async function processWithLimit<T>(
|
|
618
|
-
items: T[],
|
|
619
|
-
fn: (item: T) => Promise<void>,
|
|
620
|
-
concurrency: number
|
|
621
|
-
): Promise<void> {
|
|
622
|
-
const chunks = [];
|
|
623
|
-
for (let i = 0; i < items.length; i += concurrency) {
|
|
624
|
-
chunks.push(items.slice(i, i + concurrency));
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
for (const chunk of chunks) {
|
|
628
|
-
await Promise.all(chunk.map(fn));
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// Usage: Process 100 items, max 10 at a time
|
|
633
|
-
await processWithLimit(users, updateUser, 10);
|
|
634
|
-
```
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
---
|
|
638
|
-
|
|
639
|
-
# Caching Strategies
|
|
640
|
-
|
|
641
|
-
## Cache Patterns
|
|
642
|
-
|
|
643
|
-
### Cache-Aside (Lazy Loading)
|
|
644
|
-
```typescript
|
|
645
|
-
async function getUser(id: string): Promise<User> {
|
|
646
|
-
const cached = await cache.get(`user:${id}`);
|
|
647
|
-
if (cached) return cached;
|
|
648
|
-
|
|
649
|
-
const user = await db.findUser(id);
|
|
650
|
-
await cache.set(`user:${id}`, user, { ttl: 3600 });
|
|
651
|
-
return user;
|
|
652
|
-
}
|
|
653
|
-
```
|
|
654
|
-
|
|
655
|
-
### Write-Through
|
|
656
|
-
```typescript
|
|
657
|
-
async function updateUser(user: User): Promise<void> {
|
|
658
|
-
await db.saveUser(user);
|
|
659
|
-
await cache.set(`user:${user.id}`, user);
|
|
660
|
-
}
|
|
661
|
-
```
|
|
662
|
-
|
|
663
|
-
### Write-Behind (Write-Back)
|
|
664
|
-
```typescript
|
|
665
|
-
async function updateUser(user: User): Promise<void> {
|
|
666
|
-
await cache.set(`user:${user.id}`, user);
|
|
667
|
-
await queue.add('sync-to-db', { user }); // Async persistence
|
|
668
|
-
}
|
|
669
|
-
```
|
|
670
|
-
|
|
671
|
-
## Cache Invalidation
|
|
672
|
-
|
|
673
|
-
```typescript
|
|
674
|
-
// Time-based expiration
|
|
675
|
-
await cache.set('key', value, { ttl: 3600 });
|
|
676
|
-
|
|
677
|
-
// Event-based invalidation
|
|
678
|
-
eventBus.on('user.updated', async (userId) => {
|
|
679
|
-
await cache.delete(`user:${userId}`);
|
|
680
|
-
});
|
|
681
|
-
|
|
682
|
-
// Pattern-based invalidation
|
|
683
|
-
await cache.deleteByPattern('user:*');
|
|
684
|
-
```
|
|
685
|
-
|
|
686
|
-
## HTTP Caching
|
|
687
|
-
|
|
688
|
-
```typescript
|
|
689
|
-
// Cache-Control headers
|
|
690
|
-
res.setHeader('Cache-Control', 'public, max-age=3600');
|
|
691
|
-
res.setHeader('ETag', etag(content));
|
|
692
|
-
|
|
693
|
-
// Conditional requests
|
|
694
|
-
if (req.headers['if-none-match'] === currentEtag) {
|
|
695
|
-
return res.status(304).end();
|
|
696
|
-
}
|
|
697
|
-
```
|
|
698
|
-
|
|
699
|
-
## Best Practices
|
|
700
|
-
|
|
701
|
-
- Cache at appropriate layers (CDN, app, DB)
|
|
702
|
-
- Use consistent cache keys
|
|
703
|
-
- Set appropriate TTLs
|
|
704
|
-
- Monitor cache hit rates
|
|
705
|
-
- Plan for cache failures (fallback to source)
|
|
706
|
-
- Avoid caching sensitive data
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
---
|
|
710
|
-
*Generated by aicgen*
|