비동기/대기 (Async/Await)

비동기/대기 (Async/Await)

자바스크립트(JavaScript)에서 비동기/대기(Async/Await)는 프로미스(Promises)를 기반으로 비동기 작업(Asynchronous Operations)을 처리하는 문법이다. 비동기 코드를 동기 코드처럼 작성할 수 있게 하여 가독성을 높인다. 비동기/대기(Async/Await)의 정의, 동작 방식, 프로미스(Promises)와의 차이점, 그리고 사용 사례를 예제를 통해 확인한다.


비동기/대기(Async/Await)는 프로미스(Promises)의 syntactic sugar로, 비동기 프로그래밍(Asynchronous Programming)을 간소화한다. 자바스크립트(JavaScript)의 이벤트 루프(Event Loop)와 결합하여 비동기 작업의 흐름을 제어한다.


비동기/대기(Async/Await)란 무엇인가?

비동기/대기(Async/Await)는 asyncawait 키워드를 사용해 비동기 작업(Asynchronous Operations)을 처리한다. async는 함수가 프로미스(Promises)를 반환하도록 정의하며, await는 프로미스(Promises)가 해결(Resolved)될 때까지 실행을 일시 중지한다. 기본적인 예제를 살펴보자:

async function fetchData() {
 return "데이터";
}
fetchData().then(data => console.log(data)); // 데이터

async 함수는 항상 프로미스(Promises)를 반환한다. await를 사용한 예제는 다음과 같다:

async function delayedMessage() {
 const promise = new Promise(resolve => setTimeout(() => resolve("완료"), 1000));
 const result = await promise;
 console.log(result);
}
delayedMessage(); // 1초 후 "완료"

await는 프로미스(Promises)가 이행(Fulfilled)되기를 기다린 후 결과를 반환한다. awaitasync 함수 내에서만 사용 가능하다.


비동기/대기(Async/Await)의 동작 방식

비동기/대기(Async/Await)는 프로미스(Promises)를 기반으로 작동하며, 비동기 작업을 순차적으로 처리한다. await는 코드 실행을 일시 중지하고, 프로미스(Promises)가 완료되면 값을 반환한다.


동작 방식을 예제로 확인한다:

async function sequence() {
 const first = await new Promise(resolve => setTimeout(() => resolve(1), 1000));
 const second = await new Promise(resolve => setTimeout(() => resolve(first + 1), 1000));
 console.log(second);
}
sequence(); // 2초 후 2

위 코드에서 await는 각 프로미스(Promises)가 해결될 때까지 기다리며, 순차적으로 값을 처리한다. 에러 처리를 포함한 예제는 다음과 같다:

async function withError() {
 try {
 const result = await new Promise((_, reject) => setTimeout(() => reject("오류"), 1000));
 console.log(result);
 } catch (error) {
 console.log(error);
 }
}
withError(); // 1초 후 "오류"

try/catch 블록은 await로 발생한 에러를 처리한다.


비동기/대기(Async/Await)와 프로미스(Promises)의 차이점

비동기/대기(Async/Await)는 프로미스(Promises)와 비동기 코드 작성 방식에서 차이가 있다.


1. 코드 구조

- 프로미스: then 체인을 사용한다.

function fetchPromise() {
 return new Promise(resolve => setTimeout(() => resolve("데이터"), 1000))
 .then(data => console.log(data));
}
fetchPromise(); // 1초 후 "데이터"

- 비동기/대기: 동기처럼 작성한다.

async function fetchAsync() {
 const data = await new Promise(resolve => setTimeout(() => resolve("데이터"), 1000));
 console.log(data);
}
fetchAsync(); // 1초 후 "데이터"

2. 에러 처리

- 프로미스: catch로 처리한다.

new Promise((_, reject) => setTimeout(() => reject("실패"), 1000))
 .catch(err => console.log(err)); // 1초 후 "실패"

- 비동기/대기: try/catch를 사용한다.

async function handleError() {
 try {
 await new Promise((_, reject) => setTimeout(() => reject("실패"), 1000));
 } catch (err) {
 console.log(err);
 }
}
handleError(); // 1초 후 "실패"

사용 사례

비동기/대기(Async/Await)의 활용 사례를 예제를 통해 확인한다.


1. 데이터 요청

async function getUser(id) {
 const response = await new Promise(resolve => setTimeout(() => resolve({ id, name: "철수" }), 1000));
 console.log(response.name);
}
getUser(1); // 1초 후 "철수"

2. 순차 처리

async function steps() {
 const step1 = await new Promise(resolve => setTimeout(() => resolve("1단계"), 1000));
 const step2 = await new Promise(resolve => setTimeout(() => resolve(`${step1}, 2단계`), 1000));
 console.log(step2);
}
steps(); // 2초 후 "1단계, 2단계"

3. 병렬 요청

async function parallel() {
 const [result1, result2] = await Promise.all([
 new Promise(resolve => setTimeout(() => resolve("첫 번째"), 1000)),
 new Promise(resolve => setTimeout(() => resolve("두 번째"), 2000))
 ]);
 console.log(result1, result2);
}
parallel(); // 2초 후 "첫 번째 두 번째"

4. 에러 복구

async function recover() {
 try {
 await new Promise((_, reject) => setTimeout(() => reject("문제"), 1000));
 } catch (err) {
 console.log("복구됨");
 }
}
recover(); // 1초 후 "복구됨"

5. 반복 요청

async function fetchMultiple() {
 const ids = [1, 2, 3];
 for (const id of ids) {
 const data = await new Promise(resolve => setTimeout(() => resolve(id * 2), 1000));
 console.log(data);
 }
}
fetchMultiple(); // 1초 간격으로 2, 4, 6

6. 조건부 실행

async function conditionalFetch(flag) {
 if (flag) {
 const result = await new Promise(resolve => setTimeout(() => resolve("참"), 1000));
 console.log(result);
 } else {
 console.log("거짓");
 }
}
conditionalFetch(true); // 1초 후 "참"

7. 타임아웃 처리

async function withTimeout() {
 const promise = new Promise(resolve => setTimeout(() => resolve("늦음"), 2000));
 const timeout = new Promise((_, reject) => setTimeout(() => reject("시간 초과"), 1000));
 const result = await Promise.race([promise, timeout]);
 console.log(result);
}
withTimeout().catch(err => console.log(err)); // 1초 후 "시간 초과"

8. 외부 API 호출

async function fetchApi() {
 try {
 const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
 const data = await response.json();
 console.log(data.title);
 } catch (err) {
 console.log("API 오류");
 }
}
fetchApi(); // 실제 API 응답에 따라 출력

성능과 한계

장점

- 가독성: 비동기 코드를 동기처럼 작성한다.

- 에러 처리: try/catch로 통합된다.

- 흐름 제어: 작업 순서를 명확히 한다.


한계

- 병렬성: 순차 실행이 기본이므로 병렬 처리를 별도로 구현해야 한다.

- 오용: await를 남용하면 성능이 저하될 수 있다.

불필요한 await 사용을 피하고, 병렬 작업에는 Promise.all을 고려한다.


마무리

비동기/대기(Async/Await)는 자바스크립트(JavaScript)에서 비동기 작업(Asynchronous Operations)을 처리하는 유용한 문법이다. 사용 사례를 통해 그 활용 방식을 살펴봤다.


+ Recent posts