callback

nn·2022년 5월 15일
0

다음은 지옥의 콜백 코드 예시이다.
예시를 보고 콜백체인의 문제점이 무엇인지 알아보자.

  class UserStorage {
    loginUser(id, password, onSuccess, onError) {
      
      setTimeout(() => {
        if (
          (id === 'seungha' && password === '1234') ||
          (id === 'ha' && password === '0987')
        ) {
          // 로그인 성공 시 콜백하는 함수
          onSuccess(id);
        } else {
          // 로그인 실패 시 콜백
          onError(new Error('not found'));
        }
      }, 2000);
    }
    // 로그인이 성공했을떄
    // 유저의 역할을 얻어오는 콜백 함수
    getRoles(user, onSuccess, onError) {
      setTimeout(() => {
        if (user === 'seungha') {
          // 성공 시 콜백
          onSuccess({ name: 'seungha', role: 'admin' });
        } else {
          // 실패 시 콜백
          onError(new Error('no access'));
        }
      }, 1000);

    }
  }

  const userStorage= new UserStorage();
  const id = prompt('enter your id');
  const password = prompt('enter your password');

// loginUser함수 실행
  userStorage.loginUser(
    id,
    password,
    (id) => {
      // onSuccess() 
      // 로그인 성공 시 getRoles()콜백 실행
      userStorage.getRoles(
        id,
        // onSuccess()
        // 역할이 있는 경우 실행
        (userWithRole) => {
          alert(
            `hello ${userWithRole.name}, you have a ${userWithRole.role} role`);
        },
        // onError() 역할을 알 수 없는 경우 실행
        (error) => {
          console.log(error)
        }
      );
    },
    // onError() 로그인 실패 시 실행
    (error) => { 
      console.log(error); 
     }
  );

가독성 문제

함수가 어느 위치에서 어떤 식으로 연결되어 있는지, 가늠하기 어렵다.

전체적인 비즈니스 로직을 한눈에 알아보기 어렵기 때문에 유지보수나 디버깅에도 문제가 있을 수 있다.


promise

위와 같은 비동기적인 문제를 해결하기 위해 promise라는 개념을 사용할 수 있다.

promise는 자바스크립트 안에 내장되어있는 오브젝트로 콜백 함수 대신 비동기적으로 작업을 수행할 때 사용할 수 있다.

promise을 다음의 두가지를 이해해야한다.

  • State (상태)
    - pending
    오퍼레이션 수행중
    • fulfillde
      오퍼레이션 완료
    • rejected
      오퍼레이션 거절
  • Producer (promise 생성) vs Consumer (promise 소비)

Promise 생성

Promise는 클래스이므로 new키워드를 사용하여 생성 할 수 있다.
Promise의 생성자는 콜백 함수를 가지고 있으며 이 콜백 함수가 가지는 생성자는 다음과 같은 인자를 가진다.
(resolve (기능을 정상적으로 수행), reject (기능에 문제가 생겼을 때 수행))

const promise = new Promise((resolve, reject) => {
  console.log('doing something...');
  setTimeout(() => {
    resolve('seungha');
    // reject(new Error('no network'));
  }, 2000);
});

Promise의 콜백 함수는 new키워드로 Promise만드는 순간 바로 실행이 된다.


Promise 사용

생성한 Promise를 사용해보자.
Promise의 상태에 따라 기능을 체이닝하여 정의할 수 있다.

promise 
  .then(value => {  // resolve (성공)
    console.log(value);
  }) 
  .catch(error => {  // reject (실패)
    console.log(error);
  })
  .finally(() => { // 성공 실패 여부와 상관없이 수행
    console.log('finally');
  });

Promise chaining

const fetchNumber = new Promise((resolve, reject) => {
  setTimeout(() => resolve(1), 1000);
});

fetchNumber
  .then(num => num * 2)
  .then(num => num * 3)
  .then(num => {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(num - 1), 1000);
    });
  })
  .then(num => console.log(num));

then을 묶어서 비동기적인 것들을 묶어서 처리 할 수 있다.


Error Handling

여러 Promise가 함께 사용되는 경우에 오류처리를 어떻게 해야할까?

const getHen = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => resolve('🐓'), 1000);
  });
const getEgg = hen =>
  new Promise((resolve, reject) => {
    setTimeout(() => reject(new Error(`error! ${hen} => 🥚`)), 1000);
  });
const cook = egg =>
  new Promise((resolve, reject) => {
    setTimeout(() => resolve(`${egg} => 🍳`), 1000);
  });

getHen() // 
   // hen => getEgg(hen) == getEgg
   // 받아온 값을 인자로 사용할 때에는 축약하여 사용가능
  .then(getEgg)
	// getEgg함수에서 오류가 발생하더라도 전체적힌 로직의 흐름에는 문제가 생기지 않도록 대비
  .catch(error => {
  	return '🍗';
	}
  .then(cook)
  .then(console.log)
// error를 가장 마지막에서 처리
  .catch(console.log);
profile
내가 될 거라고 했잖아

0개의 댓글

관련 채용 정보