첫번째로는 synchronous와 aysynchronous에 대해서 알아보면
JS는 synchronous 즉 동기적인 프로그램이다. 바로 hoisting이 된 이후부터 코드가 작성한 순서에 맞쳐서 하나하나씩 동기적으로 실행된다는 것이다. hoisting이란 var변수와 function declaration 함수선언들이 자동적으로 제일위로 올라가는 것이 hoisting이다. hoisting된 이후부터 코드가 나타나는 순서대로 자동적으로 실행이 된다.
아래와 같이 정해진 순서에 맞게 나타난다.
aysynchronous는 비동기적으로 언제 코드가 실행될 지 예측할 수 없는 것을 말한다.
아래 예제를 보자
setTimeout이라는 web API가 있는데 브라우저에서 제공되어지는 API로 지정한 시간이 지나면 전달한 콜백함수를 호출하는 것이다. 콜백함수라는 것은 사용자가 전달한 함수를 나중에 불러줘라고 이해하면 된다.
setTimeout에는 handler 즉, TimerHandler라는 콜백함수를 전달해주고 어느정도 시간을 지정할 건지 timeout이 있다.
(시간은 ms, 1000ms = 1second)
아래와 같이 작성하면 1초뒤에 2가 출력이된다.
자바스크립트 엔진은 코드를 위에서 제일 위에서부터 밑으로 실행을 하게 되는데 콘솔로그를 만나서 1을 출력하고 그다음거는 setTimeout이니까 브라우저에게 요청이 왔다고 알리고 1초뒤에 전달해준 콜백실행해라고 한다. 그 다음 응답을 기다리지 않고 콘솔로그 넘어가서 3을 출력하게 된다. 브라우저에서 1초가 지나면 콜백함수 실행하라고 하고 2가 출력된다. 이러한 것이 asynchronous한 방법이다.
여기서 실행한 함수는 바로 실행안되고 setTimeout함수안에 하나의 파라미터 인자로 지정한 만든함수를 전달해주는데 1초가 지난뒤에 실행해줘라고 해서 Callback라고 부른다. arrow function으로 아래그림과 같이 나타낼 수 있다.
여기까지 동기와 비동기에 대해서 알아보았다.
또 콜백도 두가지의 경우가 나눠진다.
동기적으로 실행하는 콜백과 언제 실행될 지 모르는 asynchronous callback이 있다.
콜백을 파라미터 인자로 받아서 처리하는 함수를 만들어보자
콜백을 바로 실행하는 동기적 콜백을 보면 print라는 콜백함수를 전달받는다. js는 타입이 아니라서 어떤 타입의 콜백함수를 받는지를 예측할 수는 없지만 아무런 인자가 전달되지 않고 간단하게 hello를 콘솔로그 찍으면 1 3 hello가 출력되고 앞에 작성됐던 2가 1초뒤에 출력이 된다.
자바스크립트 엔진이 함수 선언을 제일 위로 올려놓고 1을 출력하고 브라우저한테 셋타임아웃요청하고 3 출력하고 hello있는 함수 호출해서 hello출력되고 1초뒤에 2가 출력되는 것을 볼 수가 있다.
비동기 콜백은 printWithDelay를 보면
브라우저API를 이용해서 print라는 콜백함수를 호출하고 timeout이라는 인자를 넣고 전달된 print와 timeout을 setTimeout에 요청하는 것이다. 원하는 기능을 동작하는 콜백함수를 전달해야하고 2초뒤에 출력되게 하면 아래 콘솔창과 같이 나타난다
자바스크립트 엔진이 모든함수의 선언은 호이스팅 되기 때문에 아래와 같은 순서대로 실행이 될 것이다.
1출력 셋타임아웃 브라우저한테 요청해놓고 3출력 printImmediately함수가 호출해서 바로 출력하고 그 다음에 printWithDelay도 브라우저한테 요청하고 브라우저에서 1초시간 지난 다음에는 콜백이 실행되서 2가 출력되고 2초뒤에는 콜백이 실행되서 async callback가 출력된다.
결론은 콜백은 동기 비동기가 있다는 것을 유념하자
즉 JS는 함수를 콜백형태의 인자로 다른 함수에 전달할 수도 있고 변수에 할당할 수도 있는 언어이다. 언어들마다 콜백을 지원하는 방식은 차이가 있지만 JS에서는 위와같은 방식으로 콜백이 지원되는 것을 알자.
콜백안에 콜백을 부르고 부르고 하는 콜백지옥이 있다.
사용자의 데이터를 벡앤드 서버에게서 데이터를 받아오는 클래스를 작성하면 UserStorage라는 class를 만들자
UserStorage에는 두 가지의 API가 있다고 가정하면 첫번째로는 사용자를 로그인하는거 id와 password를 받아오고 로그인이 정상적으로 이뤄지면 onSuccess를 사용자 데이터와 함께 호출하고 로그인 실패하면 onError라는 콜백함수를 호출해준다.
다른 하나는 getRoles 사용자의 데이터를 받아서 사용자마다 가지고 있는(admin, guest etc...)역할들을 서버에게 요청해서 정보를 받아오는 API가 있다고 생각해보자.
원래는 사용자가 로그인하면 로그인한 사용자 정보안에 관련된 정보를 한번에 벡앤드에서 받아오는 것이 맞는데 지금은 간단하게 예제로 벡앤드가 예전에 만들어져서 사용자의 역할을 따로 네트워크에 요청해서 다시 받아와야하는 나쁜 벡앤드라고 가정해보자
사용자의 역할을 잘 받아온다면 똑같이 onSuccess를 호출하고 문제가 있으면 onError 호출해주는 함수를 만들어보자.
실제 벡앤드가 없기 때문에 setTimeout()라고 해서 딜레이를 주면서 네트워크와 통신을 하는 거처럼 만들어보자.
로그인하는데는 2초정도 걸리게 하고 loginUser라는 함수를 호출하게 되면 2초뒤에 코드블럭이 실행되고
코드는 id가 jay이고 password가 dream 이거나 id가 coder이고 password가 academy이면 전달받은 onSuccess라는 함수를 불러주는데 id를 전달해준다. 포함되지 않는 경우라면 onError를 호출해주면서 Error라는 오브젝트를 만들어서 not found라고 전달해주면 된다.
다음으로는 getRoles를 이용해 사용자가 역할을 받아올 때 1초 뒤에 코드블럭이 실행되는데 사용자가 jay이면 onSuccess를 호출하면서 이름은 jay이고 역할은 admin인 오브젝트를 전달해주고 jay가 아니라면 onError를 호출하면서 Error의 오브젝트를 만들면서 no access라고 전달해 준다.
클래스를 이용해서 사용자에게 아이디와 비밀번호 입력을 받아오고 입력받은 아이디와 패스워드 이용해서 서버에게 로그인해달라하고 로그인 성공적으로 되면 id를 받아오고 받아온 id를 이용해서 역할을 요청해서 받아올 것이다.
역할이 성공적으로 받아와지면 사용자의 오브젝트 이름과 역할이 들어있는 것들을 출력할것이다.
userStorage라는 변수를 선언하고 클래스니까 new라는 키워드 이용해서 UserStorage라는 클래스를 만들고
사용자에게 아이디를 받아오고 prompt라는 API를 이용해서 문구가 출력되게 하고
패스워드도 prompt를 이용해서 문구출력되게 하고
userStorage를 이용해서 loginUser()를 이용해 id와 password를 전달하고
성공을 하게되면 사용자를 받아왔을 때 코드블럭과 실패했을 때 코드블럭을 싸ㅓ주고
에러가 발생하면 콘솔로그에 에러문구가 나오게 하고
사용자가 로그인이 되었다면 사용자의 역할을 받아오고 데이터가 들어오면 이것을 처리하는 콜백함수 하나와
에러가 발생하면 출력되는 콜백함수 하나를 작성한다.
사용자가 성공적으로 로그인 되고 사용자의 역할을 잘받아왔을 때 userWithRoles를 실행하게 한다.
로그인이 잘됐다는 메세지를 alert를 이용해서 사용자의 이름과 역할이 나오게 문구를 출력한다.
콜백함수안에서 다른 것을 호출하고 또 다른 콜백을 전달하고 콜백을 전달전달하면 위의 예제가 콜백지옥인데
문제점은 가독성이 매우 떨어진다.
즉 로직을 이해하기가 너무 어렵다.(로그인 한다음에 로그인한 유저의 데이터를 받아오는구나라고 파악하기가 어렵다.)
그리고 에러가 발생하거나 디버깅을 해야되는 경우에도 굉장히 어렵다.
에러가 생기면 어떤 에러에서 문제가 생겼는지 알기 어렵다.
참고: https://www.youtube.com/watch?v=s1vpVCrT8f4&list=PLv2d7VI9OotTVOL4QmPfvJWPJvkmv6h-2&index=11
'JavaScript > DreamCoding' 카테고리의 다른 글
비동기 async와 await & Promise APIs (0) | 2021.08.03 |
---|---|
프로미스 활용하기(JavaScript Promise) (0) | 2021.08.03 |
JSON 활용방법 (0) | 2021.08.03 |
유용한 10가지 배열함수들과 Array APIs 총정리 (0) | 2021.08.03 |
배열에 대해서 / APIs 정리 (0) | 2021.08.02 |