개발기록장

[JavaScript] 콜백함수와 콜백 지옥 탈출을 위한 promise, async/await (1) 본문

TIL/JavaScript

[JavaScript] 콜백함수와 콜백 지옥 탈출을 위한 promise, async/await (1)

yangahh 2020. 12. 30. 04:22

 

 

콜백함수란?

 

자바스크립트에서는 파라미터로 함수를 전달 받을 수 있는데

이때 파라미터로 전달받아서 함수 내부에서 수행되는 이 함수를 콜백함수라고 한다.

 

 

예시)

// 예제 1 : 동기적(=즉각적)으로 실행되는 콜백함수

function printImmediately(callback) {
	callback();
}

printImmediately(function() {
	console.log('Synchronous callback function');
});



// 예제 2 : 비동기적으로 실행되는 콜백함수

function printWithDelay(print, timeout) {
  setTimeout(print, timeout);
}

printWithDelay(() => console.log("async callback"), 2000);

 

 


 

 

 

비동기로 처리하는 함수가 많을 경우 콜백함수를 많이 쓰면 '콜백 지옥'에 빠질 수 있다.

// Callback Hell 예제 >> 이렇게 쓰지 마라!!


class UserStorage {  // 사용자의 데이터를 서버에서 받아오는 클래스.
  
  // 로그인 처리 함수
  loginUser(id, password, onSuccess, onError) {
    // onSuccess : 로그인 성공 시 호출하는 콜백함수 / onError: 로그인 실패 시 호출하는 콜백함수
    setTimeout(() => {
      if (
        (id === "user1" && password === "pwpw1") ||
        (id === "user2" && password === "pwpw2")
      ) {
        onSuccess(id);
      } else {
        onError(new Error("not found")); // Error라는 오브젝트를 만들어서 'not found'를 전달
      }
    }, 2000); // 서버와 통신하는데 걸리는 시간을 표현하기 위해(=비동기 처리를 구현하기위해) 타임아웃을 준 것
  }
  
  // 로그인 후 서버로부터 유저 권한을 확인하는 함수
  getRoles(user, onSuccess, onError) {
    // onSuccess : 인증된 유저인 경우에 호출하는 함수 / onError: 인증된 유저가 아닌 경우에 호출하는 함수
    setTimeout(() => {
      // 마찬가지로 서버와 통신하는데 걸리는 시간을 구현하기 위해 타임아웃을 사용
      if (user === "user1") {
        onSuccess({ name: "user1", role: "admin" });
      } else {
        onError(new Error("no access"));
      }
    }, 1000);
  }
}



// 구현할 프로세스
// 1. 사용자에게 id, password 입력받기
// 2. 로그인
// 3. 로그인 성공 시 받아온 id로 role 받아오기
// 4. 성공적으로 role을 받아오면 name과 role 출력

let id = prompt("id를 입력해주세요.");
let password = prompt("password를 입력해주세요.");

let userStorage = new UserStorage();  // 인스턴스 생성
userStorage.loginUser(
  id,
  password,
  // loginUser 메소드의 onSuccess 콜백함수 전달 === getRoles함수 호출
  (id) => {   
    userStorage.getRoles(
      id,
      // getRoles 메소드의 onSuccess 콜백함수 전달
      (userWithRole) => {
        alert(
          `Hello ${userWithRole.name}! you have a ${userWithRole.role} role. `
        );
      },
      // getRoles 메소드의 onError 콜백함수 전달
      (error) => {
        console.log("no access");
      }
    );
  },
  // loginUser 메소드의 onError 콜백함수 전달
  (error) => {    
    console.log("error");
  }
);

 

위 예시와 같은 콜백 체인의 문제점은

 

1. 가독성이 떨어짐
2. 비즈니스 로직을 이해하기 어려움
3. 에러가 발생하거나 디버깅을 해야할때 어려움 >> 유지보수가 어려움

 

 

따라서 되도록이면 간단한 내장 함수를 제외하곤(map, forEach 등) 콜백함수 사용을 피하는게 좋다.