본문 바로가기
JavaScript/드림코딩

자바스크립트 기초(ES5+)_비동기 처리의 시작_콜백(Callback) 이해하기(콜백지옥)

by junvely 2022. 3. 24.

 

[ 동기(Synchronous)와 비동기(Asynchronous) ]

 

1. 동기와 비동기 

1) 동기(scynchrounous) : JS는 동기적이다 > hoisting이 된 이후부터, 코드가 우리가 작성한 순서에 맞춰서 하나하나씩 자동적으로 실행된다. 

*hoisting : var변수 또는 함수 선언이 가장 최상위로 올라가는 것

2) 비동기(asynchronous) : 언제 코드가 실행될지 예측할 수 없는 것을 말한다.

3) 콜백(callback) : 해당 함수 호출 시 지정된 콜백함수를 인자로 전달하여 지정 함수를 부르도록(call back)한다. -동기/비동기

// 1. 동기 : synchronous
console.log("1");
console.log("2");
console.log("3");

// 2. 비동기 : asynchronous
console.log("1");
setTimeout(() => console.log("2"), 1000); 
// setTimeout() > 1. 브라우저 API > setTimeout()함수 안에 하나의 parameter로 지정한 함수를 전달해준다.
// 2. 지금 당장 실행하지 않고, 1초 뒤에 다시 불러 달라고 전달(call back)한다. > 이러한 함수를 callback함수라고 한다.
console.log("3");

 

 

[ 콜백(callback)의 이해 ]

 

1) Synchronous callback(동기적 콜백) : 즉각적, 동기적으로 실행한다.

2) Asynchronous callback(비동기적 콜백) : 언제 실행될지 예측할 수 없다.

// Synchronous callback(동기적 콜백) : 즉각적, 동기적으로 실행한다.
function printImmediately(print) {
  print(); // 지정한 callback함수를 print인자로 받아와 실행시킨다.
} // 함수의 선언 > hoisting > 최상위로 올라간다.

printImmediately(() => console.log("hello"));

// Asynchronous callback(비동기적 콜백) : 언제 실행될지 예측할 수 없다.
function printWithDelay(print, timeout) {
  setTimeout(print, timeout);  // 지정한 (callback함수와, 2000)을 인자로 받아와 setTimeout의 (print, timeout)인자로하여 실행시킨다.
} // 함수의 선언 > hoisting > 최상위로 올라간다.

printWithDelay(() => console.log("async callback"), 2000);
// arrow 정리
// printWithDelay(function () {
//   console.log("async callback");
// }, 2000);
 

3) 콜백지옥 : 콜백함수를 계속해서 묶어놔서 콜백함수 안에서 다른 콜백함수를 계속해서 부르는 콜백지옥..

- 혼자 작성 해보기)

1. 사용자의 데이터를 서버에게서 받아오는 class 작성
2. 사용자에게 id와 password 받아오기
3. login 
4. login 성공시 > id 받아와서 roles를 요청해서 받아오면 사용자의 {이름과, 역할}을 받아온다.

 

// 콜백 지옥
class UserStorage {
  loginUser(id, password, onSuccess, onError) {
    setTimeout(() => {
      // 실제 백엔드가 없기 때문에 login시 걸리는 시간처럼 가정해 본 것
      if (
        (id === "ellie" && password === "dream") ||
        (id === "coder" && password === "academy")
      ) {
        onSuccess(id); // id 전달
      } else {
        onError(new Error("not found")); // 콜백 > new Error object에 not found 전달
      }
    }, 2000);
  }

  // role : 역할 > 사용자 개인마다의 AD,guest역할 등의 정보를 서버에 요청해서 받아오는 함수
  getRoles(user, onSuccess, onError) {
    setTimeout(() => {
      if (user === "ellie") {
        onSuccess({ name: "ellie", role: "admin" }); //object를 전달
      } else {
        onError(new Error("no access")); // 콜백 > new Error object에 not found 전달
      }
    }, 1000);
  }
}

// 사용자의 데이터를 서버에게서 받아오는 class 작성
const userStorage = new UserStorage(); // class 생성
const id = prompt("enter your id");
const password = prompt("enter your password");

// ?? : 콜벡함수에 매개변수를 담아 돌려 줄 때 오브젝트의 변수명을 지정하지 않아도 되고 전달된 오브젝트는 그냥 함수명. 을 이용해 출력하

userStorage.loginUser(
  id,
  password,
  (user) => {
    // login성공 onSuccess시
    userStorage.getRoles(
      user,
      (userWithRole) => {
        alert(
          `Hello ${userWithRole.name}, you have a ${userWithRole.role} role`
        );
      },
      (error) => {
        console.log(error);
      }
    );
  },
  (error) => {
    // login실패 onError시
    console.log(error);
  }
);
 
  • 콜백 체인의 문제점

- 가독성이 굉장히 많이 떨어진다. 연결관계나 로직을 한눈에 이해하기가 굉장히 어렵다.

- error 발생시나 디버깅 시에도 굉장히 어렵고 유지보수도 어렵다.

- promise와 acync await를 통해 비동기 코드를 깔끔하게 작성하는법, 조금 더 병렬적으로 효율적으로 네트워크 통신을 하는 법 익히기 

 

 

 

*본 포스팅은 드림코딩 유튜브강의를 정리한 내용입니다.