137 lines
5.0 KiB
Markdown
137 lines
5.0 KiB
Markdown
# 비동기 프로그래밍 (Asynchronous Programming)
|
|
|
|
자바스크립트는 단일 스레드 기반의 언어로, 한 번에 하나의 작업만 실행할 수 있는 싱글 스레드 모델을 따릅니다. 하지만 비동기 프로그래밍을 통해 여러 작업을 동시에 처리할 수 있는 것처럼 보이게 하고, 효율적인 프로그램을 만들 수 있습니다.
|
|
|
|
비동기 프로그래밍은 **시간이 오래 걸리는 작업(예: 파일 읽기, 데이터베이스 요청, API 호출)**을 실행하는 동안 다른 작업을 멈추지 않고 동시에 처리할 수 있도록 합니다.
|
|
|
|
자바스크립트의 **이벤트 루프(Event Loop)**와 **콜백 큐(Callback Queue)**는 비동기 작업을 가능하게 하는 핵심 메커니즘입니다.
|
|
|
|
## 이벤트 루프(Event Loop)
|
|
이벤트 루프는 비동기 작업이 완료되었을 때 콜백 함수를 호출하여 실행할 수 있도록 관리합니다.
|
|
|
|
* 콜 스택(Call Stack): 실행할 함수가 저장되는 공간.
|
|
* 콜백 큐(Callback Queue): 비동기 작업이 완료된 후 실행 대기 중인 콜백 함수들이 대기하는 공간.
|
|
|
|
이벤트 루프는 **콜 스택이 비어 있을 때** 콜백 큐에서 작업을 가져와 실행합니다.
|
|
|
|
## 비동기 처리 방식 비교
|
|
* 콜백 함수
|
|
- 간단한 비동기 작업에 적합
|
|
- 콜백 지옥 발생 가능
|
|
* Promise
|
|
- 가독성이 좋고 에러 처리가 간편
|
|
- 체인 길어질 경우 가독성 저하
|
|
* async/await
|
|
- 동기식 코드처럼 작성 가능, 가독성 뛰어남
|
|
- 여러 개의 비동기 처리 병렬 실행은 불편
|
|
|
|
## 콜백 함수 (Callback Function)
|
|
콜백 함수는 함수의 인자로 전달되어 특정 작업이 완료된 후 실행됩니다.
|
|
```javascript
|
|
console.log("시작");
|
|
|
|
setTimeout(() => {
|
|
console.log("3초 후 실행");
|
|
}, 3000);
|
|
|
|
console.log("끝");
|
|
// 시작
|
|
// 끝
|
|
// 3초 후 실행
|
|
```
|
|
|
|
### 콜백 지옥 (Callback Hell)
|
|
콜백 함수가 중첩되면서 코드가 복잡하고 읽기 어려워지는 문제를 콜백 지옥이라고 합니다.
|
|
```javascript
|
|
setTimeout(() => {
|
|
console.log("1단계");
|
|
setTimeout(() => {
|
|
console.log("2단계");
|
|
setTimeout(() => {
|
|
console.log("3단계");
|
|
}, 1000);
|
|
}, 1000);
|
|
}, 1000);
|
|
```
|
|
|
|
## 프로미스 (Promise)
|
|
ES6에서 도입된 Promise는 비동기 작업을 보다 깔끔하게 처리할 수 있는 방법입니다.
|
|
Promise는 대기(Pending) → 성공(Fulfilled) → 실패(Rejected) 상태를 가집니다.
|
|
```javascript
|
|
const myPromise = new Promise((resolve, reject) => {
|
|
const success = true;
|
|
if (success) {
|
|
resolve("작업 성공!");
|
|
} else {
|
|
reject("작업 실패!");
|
|
}
|
|
});
|
|
|
|
myPromise
|
|
.then(result => {
|
|
console.log(result); // 출력: 작업 성공!
|
|
})
|
|
.catch(error => {
|
|
console.error(error);
|
|
});
|
|
```
|
|
* resolve: 비동기 작업이 성공적으로 완료되었을 때 호출되는 함수입니다.
|
|
* reject: 비동기 작업이 실패했을 때 호출되는 함수입니다.
|
|
* then: Promise가 성공적으로 완료되었을 때 실행될 함수를 전달합니다.
|
|
* catch: Promise가 실패했을 때 실행될 함수를 전달합니다.
|
|
|
|
|
|
* Promise.resolve: 이미 완료된 값을 가지는 Promise를 생성합니다.
|
|
* Promise.reject: 실패한 Promise를 생성합니다.
|
|
|
|
### Promise 체이닝
|
|
then 메서드는 새로운 Promise를 반환하므로, 여러 개의 then 메서드를 연결하여 비동기 작업을 순차적으로 실행할 수 있습니다.
|
|
```javascript
|
|
promise
|
|
.then(result => {
|
|
return result + ' 추가 작업';
|
|
})
|
|
.then(result => {
|
|
console.log(result); // '작업 완료! 추가 작업' 출력
|
|
})
|
|
.catch(error => {
|
|
console.error(error);
|
|
});
|
|
```
|
|
|
|
### 병렬 처리
|
|
비동기 작업을 병렬로 실행하려면 **Promise.all**이나 **Promise.allSettled**을 사용할 수 있습니다.
|
|
```javascript
|
|
const promise1 = new Promise(resolve => setTimeout(() => resolve("1초 후 완료"), 1000));
|
|
const promise2 = new Promise(resolve => setTimeout(() => resolve("2초 후 완료"), 2000));
|
|
|
|
Promise.all([promise1, promise2]).then(results => {
|
|
console.log(results); // 출력: ["1초 후 완료", "2초 후 완료"]
|
|
});
|
|
```
|
|
* Promise.all: 여러 개의 Promise를 동시에 실행하고, 모든 Promise가 완료되었을 때 결과를 반환합니다.
|
|
* Promise.race: 여러 개의 Promise 중 가장 먼저 완료된 Promise의 결과를 반환합니다.
|
|
|
|
## async와 await
|
|
Promise를 더욱 간결하게 사용할 수 있는 방법입니다. async와 await는 비동기 작업을 동기적인 코드처럼 읽기 쉽게 작성할 수 있도록 도와줍니다.
|
|
|
|
```javascript
|
|
function fetchData() {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
resolve("데이터 로드 완료!");
|
|
}, 2000);
|
|
});
|
|
}
|
|
|
|
async function getData() {
|
|
console.log("데이터 요청 중...");
|
|
const result = await fetchData();
|
|
console.log(result); // 출력: 데이터 로드 완료!
|
|
}
|
|
|
|
getData();
|
|
```
|
|
* async: 함수가 비동기 함수임을 나타냅니다.
|
|
* await: Promise가 완료될 때까지 기다리고, 그 결과를 반환합니다.
|