오늘은 JS에서 핵심 개념인 비동기 프로그래밍에 대해 정리해봤다.
이미지 출처 : bandal
코드가 순차적으로 실행되며, 각 작업이 완료될 때까지 다음 작업이 대기하는 방식
console.log(1);
console.log(2);
console.log(3);
작업이 완료될 때까지 기다리지 않고 다음 코드를 실행하는 방식.
console.log("시작");
setTimeout(() => {
console.log("비동기 작업 완료");
}, 2000);
console.log("종료");
시작
종료
비동기작업완료
JS는 기본적으로 단일스레드 언어다. 다중스레드를 지원하는 자바와는 다르게 한 번에 하나의 작업만 처리할 수 있다.
JS는 단일스레드지만 비동기 프로그래밍을 통해 동시성을 구현한다.
Event Loop(이벤트 루프)라는 매커니즘을 사용해 비동기 작업을 관리한다.
가장 초기의 비동기 처리 방식
function fetchData(url, callback) {
// 비동기 작업 시뮬레이션
setTimeout(() => {
const data = { message: "데이터 가져오기 성공" };
callback(data);
}, 1000);
}
fetchData("test.com/api", (data) => {
console.log(data.message); // 데이터 가져오기 성공 출력
});
비동기 작업의 최종 완료(or 실패)와 그 결과값을 나타내는 객체.
function fetchData(url) {
return new Promise((resolve, reject) => {
// 비동기 작업 시뮬레이션
setTimeout(() => {
const data = { message: "데이터 가져오기 성공" };
resolve(data); // 성공시 resolve 호출
}, 1000);
});
}
fetchData("test.com/api")
.then(data => console.log(data.message))
.catch(error => console.error(error));
여러 비동기작업을 순차적으로 처리할 수 있음
fetchData("test.com/api")
.then(data => {
console.log(data.message);
return fetchData("test.com/api2"); // 새로운 프로미스 반환
})
.then(newData => {
console.log(newData.message);
})
.catch(error => console.error(error));
ES2017에서 도입된 프로미스 기반의 코드 스타일로 더 동기적인 스타일로 비동기 작업 처리.
가독성이 크게 향상됨
async
는 함수가 프로미스를 반환하도록 함await
은 프로미스가 해결될 때까지 함수 실행 일시 중지async function fetchDataAsync(url) {
try {
// await은 프로미스가 해결될 때까지 함수 실행 일시 중지
const response = await fetch(url);
const data = await response.json();
console.log(data);
return data;
} catch (error) {
console.error(error);
}
}
fetchDataAsync("test.com/api");
// 여러 비동기 작업을 순차적으로 처리
async function processData() {
try {
const data1 = await fetchDataAsync("example.com/api1");
const data2 = await fetchDataAsync("example.com/api2");
const data3 = await fetchDataAsync("example.com/api3");
console.log("모든 데이터 처리 완료:", data1, data2, data3);
} catch (error) {
console.error("데이터 처리 중 오류 발생:", error);
}
}
JS의 비동기 작업 처리는 이벤트루프를 통해 이뤄진다.
이벤트루프는 JS 엔진이 비동기 작업을 관리하는 방식이다.
console.log("1"); // 동기 작업
setTimeout(() => {
console.log("2"); // 매크로태스크
}, 0);
Promise.resolve().then(() => {
console.log("3"); // 마이크로태스크
});
console.log("4"); // 동기 작업
// 1 4 3 2 순서로 출력
// 동기작업-마이크로태스크-매크로태스크 순으로 실행