TIL30⎟JavaScript : 비동기처리 & call back hell

비동기 처리의 시작, 콜백!
1. callback
2. promise
3. async await

Synchronous VS Asynchronous?

JavaScript is synchronous!
자바스크립트는 기본적으로 동기식프로그램이다
호이스팅이 된 이 후부터 코드가 작성한 순서대로 하나하나씩 동기적으로 실행된다.

  • Hoisting : var, function declaration 함수 선언들이 자동으로 제일 위로 올라가는 것.

JavaScript의 비동기처리란 특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 JavaScript의 특성

대표적인 예로서 setTimeout이라는 웹API, 브라우저에서 제공되는 API로 지정한 시간이 지나면 우리가 지정한 콜백함수를 불러오는 것이 있다. timehandler라는 함수를 전달해주고, timeout 시간을 정해주는 인자들이 있어 콜백함수를 전달할 수 있다.

console.log('1'):
setTimeout(()=> {
 console.log('2'),
 }, 1000);
console.log('3'):
//
1
3
2

브라우저 API는 무조건 브라우저에게 요청을 보내게 되고 응답을 기다리지 않고 바로 console.log로 넘어가게 된다. 1초의 시간이 지난 다음 콜백함수를 실행해! 라고 명령하기 때문에 이것이 asynchronous 비동기적인 방법이다

콜백은 그럼 항상 비동기일때만 쓰일까? 콜백도 두 가지의 경우로 나눠지는데, 즉각적으로 동기적으로 실행할 때도 쓰인다

Synchronous callback

console.log('1'):
setTimeout(()=> {
 console.log('2'),
 }, 1000);
console.log('3'):

function printImmediately(print) {
 print();
}
printImmediately라는 함수안에 print라는 콜백을 받아서 실행하는 함수

printImmediately(()=> console.log('hello'));
아무런 인자가 전달되지 않고 간단하게 console.log를 출력하는 함수 
//
1
3
hello
2

자바스크립트 엔진이 어떻게 작동했을까?
hoisting 으로 인해 선언한 printImmediately 함수의 선언을 제일 위로 올리게 되고, 순차적으로 출력하는 것을 볼 수 있다

Hoisting이 적용된 모습

function printImmediately(print) {
 print();
}

console.log('1'):
setTimeout(()=> {
 console.log('2'),
 }, 1000);
console.log('3'):

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

Asynchronous callback

function printImmediately(print) {
 print();
}

console.log('1'):
setTimeout(()=> {
 console.log('2'),
 }, 1000);
console.log('3'):

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

function printWithDelay(print, timeout) {
  setTimeout(print, timeout);
}
printWithDelay(()=> console.log('async callback'), 2000);
//
1
3
hello
2
async callback

아까와 같이 모든 함수의 선언은 hoisting이 되기 때문에 선언이 가장 위로 올라가게 된다.

//Synchronous callback
function printImmediately(print) {
 print();
}

//Asynchronous callback
function printWithDelay(print, timeout) {
  setTimeout(print, timeout);
}

console.log('1'): 동기
setTimeout(()=> {
 console.log('2'),
 }, 1000); 비동기
console.log('3'): 동기

printImmediately(()=> console.log('hello')); 동기
printWithDelay(()=> console.log('async callback'), 2000); 비동기
//
1
3
hello
2
async callback

💡 요약

콜백에는 동기적으로 실행할 수 있는 방법도 있고, 비동기적으로 실행할 수 있는 방법이 있다. 자바스크립트는 함수를 콜백형태로 인자로 다른 함수에 전달할 수도 있고, 변수에 할당할 수도 있는 언어이다. 언어마다 콜백을 지원하는 방식은 다르다!

📎 https://www.youtube.com/watch?v=s1vpVCrT8f4

🔥 Call back Hell

콜백 지옥은 비동기처리 로직을 위해 콜백 함수를 연속해서 사용할 때 발생하는 문제이다. 웹 서비스를 개발하다보면 서버에서 데이터를 받아와 화면에 표시하기까지 인코딩, 사용자 인증 등을 처리해야 하는데, 이 모든 과정을 비동기로 처리해야한다면 이렇게 콜백 안에 콜백을 무는 코드를 짜게 된다. 이렇게 된다면 가독성도 떨어지고 로직을 변경하기도 어렵다!

사용자의 데이터를 백엔드, 서버에서 받아오는 것과 같은 클래스를 만들어보자!

loginUser라는 함수를 호출하게 되면, 2초뒤에 코드블럭을 실행하게 되는데, 코드는 id와 password가 if값에 지정된 것과 같다면 우리가 전달받은 onSuccess라는 콜백을 불러주는데, 바로 id를 전달해준다. 포함되지 않는다면 onError를 불러주면서 error라는 object를 만들어서 not found를 전달해준다.

class UserStorage { 
  loginUser(id, password, onSuccess, onError) {
   setTimeout(()=> {
    if(
     (id === 'ryan' && password === 'kakao') ||
     (id === 'jordi' && password === 'niniz')
    ) {
      onSuccess(id);
      //if를 만족한다면 onSuccess에 id를 전달
    } else {
      onError(new Error('not found'));
     //Error라는 object를 만들어서 not found라고 전달
    }
   }, 2000); 
  }
  
  getRoles(user, onSuccess, onError) {
    setTimeout(()=> {
      if(user === 'ryan') {
         onSuccess({name : 'ryan', role : 'admin'});
         } else {
             onError(new Error('no access'));
        }
     }, 1000);
   }
 } 
  1. 클래스를 이용해서, 첫 번째로 사용자에게 아이디와 패스워드를 입력을 받아올 것. 입력받아온 이것들을 이용해서 2. 서버에게 로그인 3. 로그인이 성공적으로 된 다면, 아이디를 다시 받아와서, 받아온 아이디를 이용하여 roles 요청해서 성공적으로 받아진다면 우리에게는 4. name과 role이 있는 걸 출력할 것이다

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

userStorage.loginUser(
    id,
    password,
    user => {
        userStorage.getRoles(
            user,
            userWithRole => {
                alert(`Hello ${userWithRole.name}, you have a ${userWithRole.role}`
                );
            },
            error => {
                console.log(error);
            }
        );
    },
error => {
    console.log(error);
})

How to handle Call back hell?

코딩 패턴안에서 해결하고자 한다면 콜백 함수를 분리해주면 되지만, 일반적으로 콜백 지옥을 해결하는 방법에는 Promise나 Async를 사용하는 방법이 있다.

to be continued...!

좋은 웹페이지 즐겨찾기