Files
2nd/10_Wiki/Dev/Language/비동기_프로그래밍_Promise_async_await.md
T
Antigravity Agent 1cfd3bbb56 docs(10_Wiki): 위키 구조 정리 — 언어 튜토리얼 카테고리 폴더 제거 + 신규 자산 동기화
Topic_CSS/Topic_HTML/Topic_JavaScript/Topic_Prompt/Topic_Comfyui 등 기존 카테고리 폴더를 정리하고,
Topic_Graphic/Dev 등 신규 산출물과 Topics 내부 세션/메모리 기록을 동기화.
2026-07-05 00:10:59 +09:00

8.2 KiB

id, title, category, status, verification_status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, created_at, updated_at, review_reason, merge_history, tags, raw_sources, applied_in, github_commit
id title category status verification_status canonical_id aliases duplicate_of source_trust_level confidence_score created_at updated_at review_reason merge_history tags raw_sources applied_in github_commit
async-programming-promise-async-await 비동기 프로그래밍 Promise async await Programming_Language draft applied
Promise
async
await
비동기
AbortSignal
동시성
스트리밍
concurrency
A 0.93 2026-06-13 2026-06-13
typescript
javascript
async
promise
abortsignal
astraai
AstraAI/src/core/services.ts
AstraAI/src/core/lock.ts
AstraAI/src/core/queue.ts
AstraAI/src/features/providers/index.ts
AstraAI

비동기 프로그래밍 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 결합 (핵심 패턴)

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" 가 필요하다:

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.tsPromise.all(tasks) 로 provider 목록 병렬 조회 [S5].

💻 코드 패턴 (Code patterns)

// 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)

📚 출처 (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 코드 분석 기반 초안 생성.