Engineering
JS 비동기 핵심 패턴
JS 비동기 핵심 패턴 학습 내용을 정리한 백필 노트입니다.
이 글은 2025년 학습 기록을 블로그 형식으로 정리한 백필 노트입니다.
1. 동기와 비동기의 개념
-
동기(Synchronous): 하나의 작업이 완료될 때까지 다음 작업이 대기하는 직렬적 실행 방식입니다. 코드가 작성된 순서대로 동작합니다.
console.log(1); console.log(2); console.log(3); // 출력: 1, 2, 3 -
비동기(Asynchronous): 하나의 작업이 완료되지 않아도 다음 작업을 실행할 수 있는 병렬적 실행 방식입니다. 주로 네트워크 통신과 같이 시간이 걸리는 작업에 사용되어 시스템 멈춤 현상을 방지합니다.
console.log(1); setTimeout(() => console.log(2), 0); console.log(3); // 출력: 1, 3, 2
2. 비동기 코드 처리 패턴
비동기 코드의 실행 순서를 보장하기 위한 주요 패턴은 다음과 같습니다.
콜백 (Callback) 패턴
-
특정 비동기 작업이 완료된 후 실행될 함수(콜백)를 인자로 전달하는 방식입니다.
-
문제점: 비동기 작업을 순차적으로 여러 번 처리해야 할 경우, 콜백 함수가 계속 중첩되어 코드의 가독성이 떨어지고 복잡해지는 **콜백 지옥(Callback Hell)**이 발생할 수 있습니다.
a(() => { b(() => { c(() => { // ... }); }); });
Promise와 .then() 패턴
-
ES2015에서 도입된
Promise객체를 사용하여 콜백 지옥 문제를 해결합니다. -
비동기 작업의 완료 시점을
.then()메소드로 보장받을 수 있습니다. -
.then()메소드에서 다시Promise객체를 반환함으로써 중첩 없이 체인 형태로 코드를 작성할 수 있어 가독성이 향상됩니다.a() .then(() => b()) .then(() => c());
async/await 패턴
-
ES2017에서 도입된 가장 최신 방식으로, 비동기 코드를 동기 코드처럼 직관적으로 작성할 수 있게 합니다.
-
async키워드가 붙은 함수 안에서만await키워드를 사용할 수 있습니다. -
await은Promise가 완료될 때까지 함수의 실행을 기다립니다.(async () => { await a(); await b(); await c(); })();
3. Promise 심화
Promise는 비동기 작업의 상태를 나타내는 객체로, 세 가지 상태를 가집니다.- 대기 (Pending): 작업이 시작되었지만 아직 완료(이행 또는 거부)되지 않은 상태.
- 이행 (Fulfilled): 작업이 성공적으로 완료된 상태.
resolve(결과)를 통해 값을 전달합니다. - 거부 (Rejected): 작업이 실패한 상태.
reject(이유)를 통해 에러를 전달합니다.
4. 에러 핸들링 (Error Handling)
-
콜백 방식: 성공, 실패, 최종 실행 콜백을 각각 전달하여 처리합니다.
-
.then()방식:.catch()메소드로 실패(거부) 상태를 처리하고,.finally()메소드로 성공/실패 여부와 관계없이 항상 실행되어야 하는 코드를 처리합니다.promise .then(res => console.log(res)) .catch(err => console.error(err)) .finally(() => console.log('종료!')); -
async/await방식:try...catch...finally구문을 사용하여 동기 코드와 유사한 방식으로 에러를 처리합니다.try { const res = await promise; } catch (err) { console.error(err); } finally { console.log('종료!'); }
5. 반복문에서의 비동기 처리
-
.forEach(),.map()과 같은 배열 메소드는await을 기다리지 않고 모든 반복을 동시에 실행하므로, 순차적인 비동기 처리에 적합하지 않습니다. -
반복문 안에서 비동기 작업을 순서대로 실행하려면
for또는for...of반복문을 사용해야 합니다.// 올바른 방법 (async () => { for (const title of titles) { const movies = await getMovies(title); console.log(title, movies); } })();
6. Promise 정적 메소드
Promise.all(promises): 모든Promise가 이행될 때까지 기다립니다. 하나라도 거부되면 즉시 전체가 거부됩니다.Promise.allSettled(promises): 모든Promise가 이행되거나 거부될 때까지 기다린 후, 각Promise의 상태와 결과를 배열로 반환합니다.Promise.race(promises): 가장 먼저 이행되거나 거부된Promise의 결과를 반환합니다.Promise.any(promises): 가장 먼저 '이행'된Promise를 반환합니다. 모든Promise가 거부될 경우에만 거부됩니다.Promise.resolve(value): 무조건 이행되는Promise를 생성합니다.Promise.reject(reason): 무조건 거부되는Promise를 생성합니다.
7. 활용 예제: 이미지 로드
Image객체의load와error이벤트를Promise로 감싸 비동기적으로 이미지 로딩을 처리할 수 있습니다.await을 사용하여 이미지 로드가 완료될 때까지 기다린 후, 로딩 애니메이션을 제거하고 이미지를 화면에 표시하는 로직을 구현할 수 있습니다.