Search
▪️

Understanding Async Requests

What are Async Requests?

Node.js로 만들어진 Application과 Browser, 즉, Server와 Client가 존재하는 것은 Web이든 Mobile이든 어떤 프로젝트가 되었든 이와 같은 구조를 가지는 것을 알 수 있다. (Frontend와 Backend로 구성)
이렇게 나뉘어진 상태에서 Frontend와 Backend의 소통은 Request와 Response로 이뤄져 있다. Client가 Server로 보내는 것을 Request, Server에서 Client로 보내는 것을 Response라고 한다. (Response는 이제까지는 항상 HTML Page이거나 HTML Page를 Return하는 Redirect였다.)
즉, HTML을 Response로 받는 것 자체가 Reload하는 것인데, Page를 Reload하기 싫다면 어떻게 해야하는가? Backend가 맡는 일이 증가함에 따라 Browser에서 JavaScript를 이용하게 되어 더 이상 새로운 HTML Page를 Fetch하지 않아도 된 것이 최근 추세이다. 즉, Browser에서 JavaScript를 사용하기 때문에 현 Page 위에서 변화가 만들어지는 것이다. 이는 새로운 Page를 Reloading하는 것보다 반응성이 훨씬 빠르다.
새로운 HTML Page를 그리지 않기 위해서는 기존 HTML Page 위에서, 변화하는 데이터들만 받아와서 뿌려주는 것이 필요했기 때문에, Request를 JSON으로 Server에게 보내고 원하는 데이터를 Server로부터 JSON 형식으로 Response를 받게 되었다. 이와 같은 것들이 HTML을 Return하는 것이 아니라 JavaScript를 통해서 Server와 Client가 소통하면서 가능해진 일이다.
이와 같은 과정들은 Page를 Reloading 할 필요가 없기 때문에 사용자의 동작에 Interrupt 받지 않고 Backend에서 작업을 계속해서 수행할 수 있는 것이다. (즉, Asynchronous하다.)

Adding Client Side JS Code

HTML Page를 Reloading하지 않고도, Server에서는 Request에 대한 작업들만 처리하고 Client는 기존 HTML Page 위에서 작업을 하기 위해서는 Browser에서 JavaScript를 이용하여 DOM을 제어해야만 가능하다. (Server의 도움이 조금은 필요하다.)
위와 같은 작업을 Asynchronous JavaScript Request라고 한다.
이렇게 작성된 JavaScript Code들은 Browser에서 쓰이고, Browser에서 보이기 때문에 Public으로 둔다. 프로젝트의 구조는 public/js와 같이 두는 것이 일반적이다. 또한 작성된 JavaScript Code들은 Browser에서 작동하기 때문에 View에 작성된 Script들에 Import 되어야 한다.
Import하는 방법은 Footer아래에 Script Source로 넣어주면 된다. (public 폴더는 static으로 설정했기 때문에 Root로 인식하는 점을 고려하여 src를 할당한다.) 아래와 같이 할당하면 된다.
<script src="$scriptPath"></script>
이렇게 Import한 JavaScript Code는 DOM이 Render되면서 실행하게 된다.
Button에 대해서 기존 HTML Page에서 작업하게 하려면, type을 submit이 아니라 button으로 주고, JavaScript Code를 이용해야 한다. 또한 Button을 눌렀을 때 Request를 보내게 했던 Form도 지워야 한다. (해당 Form이 HTTP Method를 통해서 x-www-form-urlencoded로 Request를 보내게 되므로 말이다.)
Form이 사라졌으므로 원래 Form으로 보냈던 데이터들을 Manual하게 모아줘야 한다. 그렇다면 Form으로 자동으로 데이터들을 모아서 Submit을 감지했던 것과 달리, Form을 삭제 했으면 이를 어떻게 처리해야 하는가? → 해당 데이터들을 Tag ID로 모으고, 버튼 클릭을 감지하는 Listener를 두는 식으로 처리를 해야 한다.
Button에 onclick을 두어 클릭 시 수행할 Method를 지정 했다면, 해당 Method는 주변 Element들을 제어할 수 있어야 한다. 그렇다면 주변 Element는 어떻게 접근하는가? onclick에 둔 Method의 인자로 this를 보내주어, 주변 Element에 접근할 수 있도록 한다. 조금 더 자세히 설명하면, this 자체만으로 주변 Element에 접근할 수 있는 것이 아니다. 다만, 이렇게 쓰인 this는 Click 되었을 시 Click된 Element를 참조하게 되는데, 이를 통해서 주변 Element에 접근할 수 있는 것이다.
예를 들어서 Button 주변에 name으로 nearElement로 쓰이고 있는 Element에 접근하고 싶다면, $button.parentNode.querySelector('[name=nearElement]')로 nearElement의 Element에 접근할 수 있는 것이다. 만일 해당 Element의 값을 추출하고 싶다면, $button.parentNode.querySelector('[name=nearElement]').value로 접근 가능하다.

Sending & Handling Background Requests

새로운 HTML Page를 Render하는 것이 아니라 기존 HTML Page를 이용한 것은 바뀌는 데이터를 처리하는 것이고 이에 대해서 Response를 HTML로 보내는 것이 아닌 JSON으로 보내는 것이다.
response.json()으로 응답을 보내기 전에, 일반적으로 Status를 먼저 정해서 보내는 것이 좋다. (Error Catch 역시도 Error Handling Middeware로 보내는 것이 아니라 response.json()으로 보낸다.)
이와 같이 json으로 처리하는 Reloading이 없는 요청의 경우 View페이지의 Form등을 통해서 요청 하는 것이 아니라, Browser의 DOM을 제어하는 JavaScript Code에서 요청을 보내는 것이 일반적이다.
Asynchronous JavaScript Code에서는, Browser단에서 HTTP Request를 보내는 것을 지원하는 fetch() Method를 통해서 HTTP Request를 보낼 수 있다.
Broswer 단에서 지원하는 HTTP Request 요청을 날리는 fetch() Method의 인자로, 첫 번째는 Routing Path, 두 번째 인자로는 method 및 headers와 같은 Routing Option들을 Object로 보낼 수 있다.
일반적으로 Request 역시 JSON 데이터를 보내게 되지만, Delete Method같은 경우는 JSON 데이터를 담지 않은 비어 있는 Request Body여도 무방하다. 그저 Server에서 JSON을 Parsing하여 처리하는 것만으로도 충분할 수 있기 때문이다.
하지만 이처럼 Parsing하여 처리하기 위해서는 JSON 데이터를 처리할 수 있는 새로운 Body Parser가 필요하다. (x-www-form-urlencoded를 처리하는 Body Parser, multipart/form-data를 처리하는 Multer 둘다 JSON을 처리하지 못한다.)
Response를 JSON 데이터로 받으면 해당 데이터가 기존 HTML Page에서 바뀐 것들이므로 기존 HTML Page에서 처리해야 한다. 이는 애초에 Response를 JSON으로 받을 때부터 DOM에 의해서 처리하도록 Browser의 JavaScript에서 Response를 받아서 처리하여, 바뀐 부분에 대해서 Render하면 된다.

Manipulating the DOM

fetch() Method를 통해서 Request를 보내어 Server에서 작업 처리 후, 변경 내용을 기존 HTML에 반영하기 위해서 Response를 받아서 활용해야 한다. 이 때 받는 Response에 대해서는 .json()을 통해서 받은 데이터에 따라 처리해주면 된다.
이렇게 .json() Method를 통해서 JSON Parsing한 데이터들은, 다시 한 번 더 별도의 then() Block으로 데이터들을 처리해줘야 한다. 받은 데이터들을 토대로 DOM을 조작하는 것들을 말하는 것이다.
조작하고자 하는 Element를 찾아야 할 때는, this로 넘겨받은 Element와 this의 Ancestor를 찾는 closest() Method를 쓰면 편리하게 찾을 수 있다.
조금 불편하긴 하지만, Element는 Direct하게 접근하여 remove()할 수는 없다. 따라서 해당 Element의 Parent Node를 찾고, 이후에 removeChild($element) Method를 통해서 지우고자 하는 Element를 지정하여 삭제할 수 있다. (Internet Explorer에서 안 먹힐 수도 있기 때문이다.)