JavaScript와 Java는 동작 방식에서 근본적인 차이를 가지고 있습니다.
특히, 비동기 처리 방식에서 중요한 차이가 발생하는데요.
이번 글에서는 JavaScript의 싱글 스레드 모델과 비동기 처리 방법을 설명하고,
Java와 비교하며 Promise와 async/await을 활용한 비동기 코드 처리 방식까지 자세히 알아보겠습니다.
1️⃣ JavaScript vs Java: 스레드 모델의 차이
✅ JavaScript는 단일 스레드(Single Thread)
- JavaScript는 싱글 스레드(Single Thread) 기반의 언어입니다.
-> 즉, 한 번에 하나의 작업만 처리할 수 있습니다. - 하지만 setTimeout, fetch API 같은 비동기 함수가 존재하는데,
이 함수들은 이벤트 루프(Event Loop)와 함께 동작하여 비동기 처리가 가능합니다. - 비동기 처리가 없다면, JavaScript는 실행 중인 코드가 끝날 때까지 다른 작업을 수행하지 못하는 문제가 발생합니다.
✅ Java는 멀티 스레드(Multi Thread)
- Java는 기본적으로 멀티 스레드(Multi Thread)를 지원합니다.
-> 즉, 여러 개의 작업을 동시에 실행할 수 있습니다. - 대표적인 예로, Thread 클래스와 ExecutorService를 활용한 멀티 스레딩이 있습니다.
💡 즉, JavaScript는 기본적으로 싱글 스레드이지만,
비동기 처리 기법을 활용해 마치 멀티 스레드처럼 동작할 수 있습니다!
2️⃣ JavaScript에서 비동기 처리 방법
JavaScript에서 비동기 처리를 위해 사용되는 주요 기법은 다음과 같습니다.
기법 | 설명 |
setTimeout() | 지정된 시간 후에 특정 코드를 실행 |
setInterval() | 일정 간격으로 특정 코드를 반복 실행 |
콜백 함수 (Callback) | 비동기 작업이 끝난 후 실행될 함수를 전달 |
Promise | 비동기 작업의 완료 상태를 나타내는 객체 |
async/await | Promise를 더 쉽게 다룰 수 있도록 도와주는 문법 |
3️⃣ 콜백 함수와 콜백 지옥(Callback Hell) 문제
초기 JavaScript에서는 비동기 처리를 위해 콜백 함수를 사용했습니다.
function fetchData(callback) {
setTimeout(() => {
console.log("데이터 로딩 완료!");
callback();
}, 2000);
}
fetchData(() => console.log("다음 작업 실행"));
하지만, 여러 개의 비동기 작업을 연달아 실행해야 한다면 콜백 지옥(Callback Hell) 문제가 발생합니다.
getUser(1, function(user) {
getProfile(user, function(profile) {
getFriends(profile, function(friends) {
console.log(friends);
});
});
});
이런 가독성 문제를 해결하기 위해 Promise와 async/await이 등장했습니다.
4️⃣ Promise란?
📌 Promise 개념
Promise는 비동기 작업이 완료되었을 때 결과 값을 반환하거나, 실패했을 때 오류를 반환하는 객체입니다.
비동기 작업의 상태를 추적할 수 있도록 해주며, 콜백 지옥을 해결하는 데 도움을 줍니다.
✅ Promise의 3가지 상태
상태(State) | 설명 |
pending | 대기 중 (비동기 작업이 아직 완료되지 않음) |
fulfilled | 작업 성공 (비동기 작업이 정상적으로 완료됨) |
rejected | 작업 실패 (에러 발생) |
const myPromise = new Promise((resolve, reject) => {
let success = true;
if (success) {
resolve("작업 완료!");
} else {
reject("작업 실패!");
}
});
console.log(myPromise); // Promise { <pending> }
✅ Promise 사용법
myPromise
.then(result => console.log(result)) // 성공하면 실행
.catch(error => console.log(error)) // 실패하면 실행
.finally(() => console.log("작업 종료"));
✅ Promise 체이닝
콜백 지옥을 해결하기 위해 then()을 연결해서 사용합니다.
getUser(1)
.then(user => getProfile(user))
.then(profile => getFriends(profile))
.then(friends => console.log(friends))
.catch(error => console.error(error));
5️⃣ async/await란?
📌 async/await 개념
async/await은 Promise를 더 쉽게 사용할 수 있도록 도와주는 문법입니다.
비동기 코드를 동기 코드처럼 작성할 수 있어 가독성이 좋아집니다.
✅ async 함수
async function getData() {
return "Hello World!";
}
getData().then(data => console.log(data)); // "Hello World!" 출력
✅ await 키워드
await을 사용하면 Promise가 완료될 때까지 기다렸다가 결과를 반환합니다.
async function fetchData() {
let response = await new Promise(resolve => {
setTimeout(() => resolve("데이터 로딩 완료!"), 2000);
});
console.log(response);
}
fetchData();
✅ 에러 처리 (try-catch)
async function fetchData() {
try {
let data = await new Promise((resolve, reject) => {
setTimeout(() => reject("데이터 로딩 실패!"), 2000);
});
console.log(data);
} catch (error) {
console.error("에러 발생:", error);
}
}
fetchData();
6️⃣ Promise vs async/await 비교
항목 | Promise | async / await |
가독성 | .then() 체이닝이 길어질 수 있음 | 동기 코드처럼 읽기 쉬움 |
에러 처리 | .catch() 사용 | try-catch 사용 |
코드 구조 | 콜백을 중첩하지 않으려면 체이닝 필요 | 동기적인 방식처럼 깔끔하게 작성 가능 |
사용 용도 | 비동기 작업을 여러 개 연결할 때 | 단순한 비동기 코드 처리 시 유용 |
✅ 어떤 것을 사용할까?
- 단순한 비동기 작업 → async/await
- 여러 개의 비동기 작업을 순차적으로 실행 → async/await
- 병렬로 실행되는 여러 개의 비동기 작업이 필요한 경우 → Promise.all()
- 비동기 작업을 동적으로 연결해야 하는 경우 → Promise.then()
🎯 결론
- JavaScript는 싱글 스레드 기반이지만 비동기 처리 기법을 통해 멀티 태스킹이 가능하다.
- 콜백 함수는 가독성이 낮고, 콜백 지옥을 유발할 수 있다.
- Promise는 비동기 작업의 상태를 관리하고, 체이닝을 통해 콜백 지옥을 해결한다.
- async/await은 Promise를 더 직관적으로 사용할 수 있도록 도와준다.
- Promise와 async/await을 적절히 조합하여 효율적인 비동기 처리 코드를 작성하자! 🚀
'Front end > JavaScript' 카테고리의 다른 글
[JavaScript] Call by Value 와 Call by Reference (0) | 2025.04.02 |
---|---|
[JavaScript] location.replace와 location.href의 차이점 (0) | 2024.07.11 |
[JavaScript] var / let / const (중복선언, 재할당, 스코프) (0) | 2024.02.20 |