콜백 지옥(Callback Hell)

Onew·2025년 10월 21일
0

js

목록 보기
21/24

💡 전체 개념 요약

  • fetchData()비동기 데이터 요청 함수 (setTimeout으로 시뮬레이션된 요청)
  • 비동기 작업을 순서대로(이름 → 나이) 실행하려면
    콜백 함수 안에서 다른 비동기 함수를 또 호출해야 함
  • 이처럼 콜백 안에 콜백이 중첩되는 구조를 → “콜백 지옥(callback hell)” 이라고 함

🧩 코드 해석

document.querySelector("#request-btn3").addEventListener("click", () => {
  console.log("메인 작업 시작");
  • 버튼 클릭 시 이벤트 발생
  • "메인 작업 시작" 출력
  • 이후 데이터 요청(비동기 작업) 진행

🧠 첫 번째 시도 (주석처리된 부분)

/*
fetchData(responseData => console.log(responseData.name));
fetchData(responseData => console.log(responseData.age));
*/

이건 순차 실행이 보장되지 않는 잘못된 방법이에요 ⚠️

이유:

  • fetchData()비동기 함수라서
    두 요청이 거의 동시에 실행됨
  • 따라서 이름이 먼저 출력된다는 보장이 없음

📜 실행 예시 (비정상적인 순서 가능)

메인 작업 시작
메인 작업 종료
20
홍길동

이처럼 순서가 섞일 수 있어요.


✅ 순차 실행을 보장하는 “콜백 중첩 구조”

fetchData((responseData) => { 
  console.log(responseData.name);   // ① 이름 출력
  // 그다음 작업 - 나이 출력
  fetchData((responseData) => {
    console.log(responseData.age);  // ② 나이 출력
  }); 
});
  • 첫 번째 fetchData()가 완료되면 → 이름 출력
  • 그리고 그 안에서 다시 fetchData() 호출 → 나이 출력

📜 실행 순서

메인 작업 시작
메인 작업 종료
홍길동
20

✅ 실행 흐름 정리

순서동작
1"메인 작업 시작" 출력
2첫 번째 fetchData() 실행 (비동기 예약)
3"메인 작업 종료" 출력 (콜스택 비워짐)
4첫 번째 fetchData() 완료 → responseData.name 출력
5두 번째 fetchData() 실행 (비동기 예약)
6두 번째 요청 완료 → responseData.age 출력

⚠️ 문제점 — 콜백 지옥의 형태

이 코드가 바로 콜백 지옥(callback hell) 구조예요 👇

fetchData((data1) => {
  console.log(data1.name);
  fetchData((data2) => {
    console.log(data2.age);
    fetchData((data3) => {
      console.log(data3.city);
      // ...
    });
  });
});

➡ 들여쓰기가 계속 깊어지고,
가독성이 떨어지며,
에러 처리나 디버깅이 매우 어려움 😵


🧱 해결 방법 (예고편)

이런 콜백 지옥을 피하기 위해 등장한 게 바로 👇

  • Promise
  • async / await

이 둘을 쓰면 순차적인 비동기 코드도
동기 코드처럼 깔끔하게 작성 가능해요.


🧭 정리 요약

구분설명
fetchData()비동기 데이터 요청 함수
콜백 함수데이터 응답 후 실행될 함수
문제점순서를 보장하려면 콜백 안에 콜백을 중첩해야 함
결과코드 가독성 저하 → 콜백 지옥
해결책Promise, async/await 사용

fetchDataByPromise() 호출 이 함수는 Promise 객체를 반환해. -> Promise 객체를 반환한다는게 promise함수를 데려온다는거야?

좋은 질문이야 👍
여기서 말하는 “Promise 객체를 반환한다”는 건
“Promise 함수를 데려온다”는 뜻이 아니야 — 약간 다른 개념이야.


💡 정확한 의미

fetchDataByPromise() 함수 안을 보면 👇

function fetchDataByPromise() {
  return new Promise((resolve) => {
    const responseData = { name: "홍길동", age: 20 };
    resolve(responseData);
  });
}

여기서 new Promise(...)Promise 객체를 새로 “만드는” 코드야.
그래서 이 함수가 실행되면 👉
Promise 객체를 “리턴(반환)”하는 거야.


🧩 비유로 이해해볼까?

  • Promise 함수(생성자) = 설계도
  • Promise 객체 = 그 설계도로 실제 만든 결과물

즉,

return new Promise(...)

"Promise 설계도를 이용해서 새 Promise 객체를 만들고,
그걸 밖으로 돌려준다(반환한다)"
는 뜻이야.


🧠 그래서 “반환한다”는 건?

→ “Promise 객체를 밖으로 보내준다”는 뜻이야.
→ 즉, 이 함수를 호출하는 쪽에서 .then() 같은 걸 붙일 수 있게 되는 거야.

예를 들어 👇

fetchDataByPromise()
  .then((data) => console.log(data));

여기서 .then()을 붙일 수 있는 이유는,
fetchDataByPromise()Promise 객체를 반환하기 때문이야.
(return이 없었다면 .then() 못 붙임)


🪄 요약

표현의미
“Promise 객체를 반환한다”함수가 실행된 후, Promise 형태의 결과물을 돌려준다
“Promise 함수를 데려온다”❌ 잘못된 표현 (Promise 생성자 함수 자체를 가져오는 게 아님)
실제로 하는 일new Promise()로 Promise 객체를 새로 만들고, 그걸 return 함

원하면 fetchDataByPromise() 실행 시 실제 내부에서 일어나는 과정을 스택 + 마이크로태스크 큐 흐름으로 시각화해줄까?
(콜스택에 뭐 들어가고 언제 resolve가 실행되는지 단계별로)


😊 이해 점검 문제


fetchDataByPromise() 함수가 실행되면 무엇을 반환하지?



그 반환된 게 Promise 객체라면, 그 객체 안에서는 언제 resolve()가 실행되는 거야?



resolve(responseData)가 실행되면 .then() 메서드는 언제, 어떤 데이터를 받게 돼?



만약 fetchDataByPromise() 함수 안에서 return new Promise(...) 대신
그냥 console.log("hi")만 하고 끝낸다면,
밖에서 fetchDataByPromise().then(...) 이렇게 쓸 수 있을까?


답 👇

✅ ① fetchDataByPromise()가 반환하는 것

정답: Promise 객체
완벽하게 맞았어!
→ 즉, 이 함수는 “지금은 결과를 모르지만, 나중에 결과(성공/실패)를 줄게” 라고 약속하는 객체를 반환해.


✅ ② resolve()는 언제 실행되는가

정답: Promise 안의 비동기 작업(예: setTimeout, fetch 등)이 끝났을 때 호출돼.
그래서 “비동기 작업이 완료되면 그때 결과 데이터를 넘겨줘”라는 의미야.
→ 너가 쓴 “promise함수가 실행되고 나서”도 거의 맞아.
정확히는 “promise 안의 비동기 코드가 끝났을 때” 실행되는 거야.


✅ ③ resolve(responseData)가 실행되면

정답: 그 순간 .then()에 연결된 콜백이 실행되고, responseData가 그 콜백의 인자로 전달돼.
즉,

resolve(responseData);

👇

.then((responseData) => { ... })

이 콜백이 그 데이터를 받게 되는 구조야.
너 말한 “끝날 때 데이터를 받게 됨” → 아주 정확해! 👍


⚠️ ④ return이 없으면 .then()을 쓸 수 있을까?

정답: ❌ 불가능해.
왜냐하면 fetchDataByPromise() 함수가 Promise 객체를 반환해야
그걸 기준으로 .then()을 체이닝할 수 있기 때문이야.

즉,

return new Promise(...);

이 구문이 있어야

fetchDataByPromise().then(...)

이렇게 쓸 수 있어.

너가 말한 “then을 쓰려면 반드시 return을 써야돼” → 정확해! (100점)
단, 이유는 “then은 Promise 객체에서만 쓸 수 있기 때문”이야.

0개의 댓글