docs(10_Wiki): 위키 구조 정리 — 언어 튜토리얼 카테고리 폴더 제거 + 신규 자산 동기화

Topic_CSS/Topic_HTML/Topic_JavaScript/Topic_Prompt/Topic_Comfyui 등 기존 카테고리 폴더를 정리하고,
Topic_Graphic/Dev 등 신규 산출물과 Topics 내부 세션/메모리 기록을 동기화.
This commit is contained in:
Antigravity Agent
2026-07-05 00:10:59 +09:00
parent a397bc4720
commit 1cfd3bbb56
1495 changed files with 68534 additions and 27 deletions
@@ -0,0 +1,131 @@
---
id: async-programming-promise-async-await
title: "비동기 프로그래밍 Promise async await"
category: "Programming_Language"
status: "draft"
verification_status: "applied"
canonical_id: ""
aliases: ["Promise", "async", "await", "비동기", "AbortSignal", "동시성", "스트리밍", "concurrency"]
duplicate_of: ""
source_trust_level: "A"
confidence_score: 0.93
created_at: 2026-06-13
updated_at: 2026-06-13
review_reason: ""
merge_history: []
tags: ["typescript", "javascript", "async", "promise", "abortsignal", "astraai"]
raw_sources: ["AstraAI/src/core/services.ts", "AstraAI/src/core/lock.ts", "AstraAI/src/core/queue.ts", "AstraAI/src/features/providers/index.ts"]
applied_in: ["AstraAI"]
github_commit: ""
---
# [[비동기 프로그래밍 Promise async await]]
## 🎯 한 줄 통찰 (One-line insight)
`async/await` 는 비동기 코드를 동기처럼 읽히게 하는 문법이고, `Promise` 는 그 토대이며, AstraAI 는 여기에 **`AbortSignal` 결합·타임아웃 경쟁(race)·동시성 제한**을 더해 "취소 가능하고 폭주하지 않는" 비동기를 구현한다 [S1][S2].
## 🧠 핵심 개념 (Core concepts)
1. **Promise:** 미래의 값을 담는 객체. `pending → fulfilled/rejected` 상태를 가진다. `new Promise((resolve, reject) => ...)` 로 직접 만들거나 `async` 함수가 자동 반환한다 [S2].
2. **async/await:** `async` 함수 안에서 `await promise` 는 Promise 가 풀릴 때까지 기다린 ** 을 돌려준다. 실패하면 예외로 던져져 `try/catch` 로 잡는다 [S1].
3. **`Promise.all` / `Promise.race`:** `all` 은 모두 완료될 때까지 병렬 대기(하나라도 실패 시 전체 reject), `race` 는 가장 먼저 끝난 하나를 채택 — AstraAI 는 race 로 "작업 vs 타임아웃" 경쟁을 만든다 [S3].
4. **`AbortSignal` / `AbortController`:** 진행 중인 비동기(특히 `fetch`)를 외부에서 취소하는 표준 메커니즘. `AbortSignal.timeout(ms)`, `AbortSignal.any([...])` 로 타임아웃·사용자 취소를 결합 [S1].
5. **동시성 제한 (Concurrency limiting):** 무한 병렬은 자원을 고갈시킨다. 큐로 동시 실행 수를 `max(2, cpus-1)` 로 제한 [S4].
## 🧩 추출된 패턴 (Extracted patterns)
- **타임아웃 + 외부 취소 신호 결합:** `AbortSignal.any([req.signal, AbortSignal.timeout(timeoutMs)])` — 둘 중 무엇이 먼저 fire 돼도 fetch 가 즉시 중단된다. 사용자가 "Stop" 을 누르면 LLM 생성 도중에도 끊긴다 [S1].
- **race 로 데드락 방지:** lock 획득 시 `Promise.race([previousPromise, timeoutPromise])` — 앞 작업이 영원히 안 끝나도 timeout 이 깨운다 [S2].
- **resolve 를 밖으로 빼내는 deferred:** `let release; new Promise(r => { release = r; })` — Promise 를 만들고 그 resolve 함수를 외부에서 호출 가능하게 보관(락 해제 함수로 반환) [S2].
- **큐 기반 동시성 캡:** `enqueue<T>` 가 Promise 를 반환하되 실제 실행은 `activeCount < limit` 일 때만 — 초과분은 대기 [S4].
- **best-effort 비차단:** `void ensureEmbeddingConfigured(context)` — 결과를 기다리지 않고 백그라운드로 흘려보내는 fire-and-forget (`void` 로 의도 명시) [S1].
## 📖 세부 내용 (Details)
### await 의 실패는 예외다
`await fetch(...)` 가 네트워크 오류로 reject 되면 그 지점에서 throw 된다. AstraAI 의 `AIService.chat` 은 엔진별 루프 안에서 `try/catch` 로 잡아 `lastError` 에 저장하고 다음 엔진으로 폴백한다 — "한 엔진 실패가 전체 실패가 아니다" [S1].
### AbortSignal 결합 (핵심 패턴)
```typescript
const timeoutSignal = AbortSignal.timeout(timeoutMs);
const combinedSignal = req.signal
? AbortSignal.any([req.signal, timeoutSignal]) // 사용자 취소 OR 타임아웃
: timeoutSignal;
const res = await fetch(apiUrl, { /* ... */ signal: combinedSignal });
```
이 패턴 덕분에 (1) 응답이 너무 느리면 타임아웃으로, (2) 사용자가 멈추면 외부 signal 로 즉시 중단된다. 긴 multi-turn 경로(dispatcher 등)에는 반드시 `signal` 을 전달하는 것이 규칙 [S1].
### 직접 만드는 Promise (deferred 패턴)
락 매니저는 "다른 코드가 부를 때 풀리는 Promise" 가 필요하다:
```typescript
let release!: () => void;
const newPromise = new Promise<void>((resolve) => { release = resolve; });
// ... 작업이 끝나면 호출부가 release() 를 부르면 newPromise 가 fulfilled
return () => { release(); /* cleanup */ };
```
### 병렬 vs 순차
- 독립 작업은 `Promise.all([a(), b()])` 로 병렬 (provider 모델 목록 동시 조회) [S5].
- 의존 작업은 순차 `await a(); await b();`.
- 자원 부담이 큰 대량 작업은 `Promise.all` 대신 동시성 제한 큐를 쓴다 [S4].
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
- **`Promise.all` 의 함정:** 하나라도 reject 되면 전체가 reject 되고 나머지 성공 결과를 잃는다. 부분 실패를 허용해야 하면 `Promise.allSettled` 를 쓰거나 각 작업을 try/catch 로 감싸야 한다.
- **`await` in loop vs 병렬:** 루프 안 `await` 는 순차 실행이라 느릴 수 있다. 단, AstraAI 의 엔진 폴백 루프는 *의도적으로 순차* (앞 엔진이 성공하면 뒤는 안 부름).
- **`forEach` + async 주의:** `array.forEach(async ...)` 는 완료를 기다리지 않는다. 대기하려면 `for...of` + `await` 또는 `Promise.all(array.map(...))`.
## 🛠️ 적용 사례 (Applied in summary)
- `AstraAI/src/core/services.ts` — AbortSignal 결합 + 엔진 폴백 루프(try/catch 순차) [S1].
- `AstraAI/src/core/lock.ts` — deferred Promise + `Promise.race` 타임아웃 [S2].
- `AstraAI/src/core/queue.ts` — 동시성 제한 큐 [S4].
- `AstraAI/src/features/providers/index.ts``Promise.all(tasks)` 로 provider 목록 병렬 조회 [S5].
## 💻 코드 패턴 (Code patterns)
```typescript
// 1) 타임아웃 + 외부 취소 결합 (src/core/services.ts)
const timeoutSignal = AbortSignal.timeout(timeoutMs);
const combinedSignal = req.signal ? AbortSignal.any([req.signal, timeoutSignal]) : timeoutSignal;
const res = await fetch(apiUrl, { method: 'POST', body: JSON.stringify(payload), signal: combinedSignal });
// 2) try/catch 폴백 루프 — 한 엔진 실패가 전체 실패가 아님 (src/core/services.ts)
let lastError: Error | null = null;
for (const engine of engines) {
try { const r = await callEngine(engine); if (r) return r; }
catch (e: any) { lastError = e instanceof Error ? e : new Error(String(e)); }
}
throw lastError ?? new Error('All engines failed.');
// 3) deferred Promise + race 타임아웃 (src/core/lock.ts)
let release!: () => void;
const newPromise = new Promise<void>((resolve) => { release = resolve; });
const timeoutPromise = new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error('Lock timed out')), timeoutMs));
await Promise.race([previousPromise, timeoutPromise]);
// 4) fire-and-forget (의도적 비대기) — void 로 명시 (src/extension.ts)
void ensureEmbeddingConfigured(context);
// 5) 병렬 수집 (src/features/providers/index.ts)
const tasks: Array<Promise<void>> = [];
tasks.push(listOpenRouterModels(ctx).then((ids) => ids.forEach(pushModel)));
await Promise.all(tasks);
```
## ✅ 검증 상태 및 신뢰도
- **상태:** draft
- **검증 단계:** applied
- **출처 신뢰도:** A
- **신뢰 점수:** 0.93
- **중복 검사 결과:** 신규 생성 (New discovery)
## 🔗 지식 그래프 (Knowledge Graph)
- **상위/루트:** [[TypeScript 기초와 타입 시스템]]
- **관련 개념:** [[동시성 제어 Lock Queue Transaction]], [[LLM 프로바이더 추상화]], [[에러 처리와 커스텀 에러]]
- **참조 맥락:** 로컬 LLM 이 fetch/취소/타임아웃/병렬 처리를 작성할 때 참조.
## 📚 출처 (Sources)
- [S1] AstraAI/src/core/services.ts — AbortSignal.any/timeout, 엔진 폴백, void fire-and-forget(extension.ts 포함)
- [S2] AstraAI/src/core/lock.ts — deferred Promise, Promise.race 타임아웃
- [S3] (general) Promise.all/race 의미론
- [S4] AstraAI/src/core/queue.ts — 동시성 제한 큐
- [S5] AstraAI/src/features/providers/index.ts — Promise.all 병렬 수집
## 📝 변경 이력 (Change history)
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.