배움 __IL/TIL 1기

TIL : 77번째- 230327 [3-4-월]

Mo_bi!e 2023. 3. 27. 20:19

※ Keep in mind

 본 내용은 웹개발과정의 강의 중 내용을 복습을 위해서 메모한 것에 불과한 것입니다. 이러한 연유로 강의내용을 오인한 나머지 오기재 및 불기재가 있을 수 있으니 '참고'만 해주시길 바랍니다. 저의 경우에도 본 내용을 단순하 읽은 것이 결코 저의 것이라고 생각하지 않습니다. 본 내용은 복습를 위한 초기 내지 중간 과정에 불과한 것이고, 이후에 내용을 보충 후 인출 및 설명하기 과정이 있어야 비로소 복습의 단추가 어느정도 마무리 되어간다고 볼 수 있습니다.

 따라서 당초에 본 내용은 비공개였습니다. 그럼에도 불구하고 본 내용을 공개한 점은 함께 공부하는 동료들과 나눔을 바탕으로 배움과 성장의 공진화라는 소기의 목적을 달성에 어느정도 도움이 될수 있기 때문이라고 생각합니다.

I. RestAPI

1. 들어가며

처음에는 백엔드방식으로 했어 get post 방식으로 했어 html에다가 또하나 JS가 더 얹여

새로운 요청방식으로 떠올라 뭘 요청? 서버에 데이터 요청해서 비동기적으로 하는거야 이거를 줄여서 AJAX라고 해

AJAX로 할거야

 

1)

JS로 요청한다는건 페이지가 아니라 데이터를 요청하는거고 이를 위한게 서버에 컨트롤러가 있어야하는거야

RestController 를 이용해서 가능해!

 

요청은 동기형 비동기형 방법 두가지가 있어

동기형이라는것은 코드절차가 순서대로 이루어지도록 하는거야

동기형은 먹통사태? 가 발생해서 좋은게 아냐 이를 해결하기 위해서 비동기로하자

 

간단하게 코드에서 true만 바꿔주면 돼! 비동기 req가 가지는 도구야

동기형 일때는 다음라인이 곧 다음순서야 비동기는 콜백함수를 하는거고 콜백은 이따가 호출해줘~! (load될 때 해줘)

같은거야

data가 도착할때 호출하면 가져다가 메뉴를 써야하는데, 메뉴를 잘받았는지 알기위해 객체를 확인하면 잘 보여

이제 ui에 데이터를 뿌려야해!

크게 2가지가 있어

 

 

2. 일반 member

(1) dataset.cid

1)

cid의 자료는 dataset에 있다

 

2)

ul.onclick = function(e){
		e.preventDefault();
	// addeventList 이거는 누적할 때 쓰는거야!
	// 람다 쓰는게 아냐 왜냐하면 지역화를 못해 
		//일부로 지역변수 쓰고싶지않을 때쓴다
		
		let tagName = e.target.tagName;
		
		console.log(tagName);
	
		
//		if(!(tagName == 'LI' || tagName == 'A'))
		if(tagName != 'LI' && tagName != 'A') //li 가 아니면 return;
			return; //두가지 조건 만족시 본 함수에서 나가게해서 못쓰게 해
		
		let el = (tagName === 'LI')? e.target : e.target.parentNode;
		console.log(el);
		console.log(el.dataset.cid);
		
//		let queryString = "";	
			
//		console.log("clicked"); //return 안되면 본 내용 이해하게끔
		
		
		let categoryId = el.dataset.cid;
		
		const request = new XMLHttpRequest();
		
		request.onload = function(){
			let menus = JSON.parse(request.responseText)
			
			console.log(menus[0]);
		}
		request.open("GET", `http://localhost:8080/menus?c=${categoryId}`,true); //브라우저에서 url을 입력하는것과 같은 요
		request.send(); //
	};

 

logel출력하면 객체가 나오고

logel.dataset.cid를 출력하면 객체의 만 나온다.

 

3. Ajax

(1) 의의

1)

Ajax란 JS이용해서 비동기 데이터(XML: 상징)요청해서 화면을 갱신하는 모든 기술을 총망라해서 Ajax라고 일컷음

 

2)

Ajax 기술의 필요성은 어떤것인가?

Ajax가 존재하기전의 웹은 수전히 'HTML기능만을 이용'하여 요청하고 모든 페이지는 서버에서 만드는 방식을 사용하였다.

 

3)

Ajax 기술을 이용

이후에는 초기 페이지만 요청하고 이후의 것은 JS를 이용하여 요청한다.

더보기

Ajax

(Asynchronous Javascript And XML)



Ajax란 자바스크립트를 이용해서 비동기 데이터(XML)를 요청해서 화면을 갱신하는 모든 기술을 총망라해서 Ajax라고 일컫는다.

 

Ajax 이전의 웹 기술

 

Ajax 기술의 필요성은 어떤 것인가? Ajax가 존재하기 전의 웹은 순전히 HTML 기능만을 이용하여 요청하고 모든 페이지는 서버에서 만드는 방식을 사용하였다.



 

페이지에서 단순히 특정 숫자 하나만 변경하려고 해도 서버에서 페이지를 새로 만들어오는 방법을 사용했다.




Ajax를 이용한 웹 기술의 변화

 

Ajax를 이용하면 페이지는 초기 페이지만 요청하고 이 후의 단순한 변화는 모두 Javascript를 이용하여 요청한다. 

 

따라서 이제는 요청하는 클라이언트가 두 가지가 되었다고 볼 수 있고 그에 따라서 서버도 페이지를 제공하는 컨트롤러와 데이터를 제공하는 컨트롤러로 나누어 볼 수 있다.

 

이 두 가지를 올바르게 구분해서 개발하지 않으면 혼선이 발생할 수 있다.



Ajax의 요청 도구

Ajax에서 사용하던 초기 도구는 아이러니하게도 윈도우즈 시스템 라이브러리였다. 그런데 이것은 올바른 방법이 아니었다. 왜냐하면 자바스크립트는 SandBox 안에서만 놀아야 하기 때문이다. 

 

윈도우 시스템의 라이브러리는 그 박스를 벗어난 시스템 라이브러리이기 때문에 흔히 이것은 해킹당했다고 봐도 무방한 일인 것이다.

 

차후에 이 기능의 순기능을 이해하고 브라우저를 만든 회사들이 자사 브라우저에 그 기능을 본떠서 XMLHttpRequest 객체를 window 객체의 속성으로 추가하면서 표준 아닌 표준 라이브러리가 되었다.

 

var request = new [window.]XMLHttpRequest();

//var request = new ActiveXObject("Microsoft.XMLHTTP");

request.open("GET", url, false);

request.send(null);

 

alert(request.responseText);

 

이 객체를 이용하여 우리는 동기형비동기형 두 가지 방법으로 요청할 수 있는 새로운 요청 방식이 생기게 되었다.

 

동기형 요청

동기형으로 요청하는 방법은 단순히 open 메소드에 마지막 인자를 false로 설정하면 된다.

request.open("GET", url, false);

 

그러면 데이터를 요청하는 send() 메소드 이후에 그 데이터가 도착하기 전까지 모든 흐름은 멈추고 결과가 올 때까지 기다리게 된다. 이런 동기형은 도착한 데이터를 사용하는 위치를 분명히 알 수 있어서 다음처럼 그 다음 줄에 도착한 결과를 사용하는 코드를 순차적으로 입력하면 된다.

 

request.open(..., false);

request.send();  // 데이터가 도착할 때까지 기다리는 함수 Blocking 함수

request.responseText 를 사용하는 코드

 

문제는 이런 방식은 순차적으로 실행되는 방식을 따르기 때문에 코드를 이해하는 난이도는 낮아지지만 네트워크 상태가 좋지 않거나 서버의 응답이 느린 경우는 …. 화면이 멈추는 일이 발생한다.

 

이런 방식의 문제를 해결하려면 요청 방식을 비동기로 처리해야 한다.

 

비동기형 요청

비동기형으로 요청하는 방법은 앞에서 언급했던 것처럼 open 메소드에서 마지막 인자를 true로 설정하거나 아예 그 인자를 설정하지 않으면 기본값이 비동기처리가 된다.

 

request.open("GET", url, true);  또는 request.open("GET", url);

 

이렇게 비동기로 요청을 설정하게 되면 흐름은 순서와 달라지게 된다.

 

request.send() // 비동기로 요청했으므로 데이터가 도착할 때까지 흐름은 새로 만들어지고 메인 흐름은 막지 않고 바로 패스 시킨다.

request.responseText 를 사용하는 코드

 

따라서 responseText는 데이터를 받지 못한 상태에서 사용될 수 있기 때문에 이 부분에서 오류가 발생할 수 있다.

 

Callback 함수를 이용한 데이터 처리

 

앞서 언급했던 것처럼 비동기로 요청하게 되면 요청 이후의 데이터는 별도의 다름 흐름에서 처리되므로 그 별도의 흐름에서 내가 처리할 로직을 실행할 수 있도록 함수를 위임하는 방법을 사용한다.

 

 

 

위임된 함수는 바로 실행되는 것이 아니라 나중에 load가 완료되면 실행되는 또는 호출되는 함수라고 해서 붙여진 이름이 CallBack이다.

 

이 함수는 메인 흐름에서 호출되지 않으며 request가 가지는 별도의 흐름에서 ‘로드가 완료되는 순간 실행’되는 함수이기 때문에 이벤트 함수라고도 불리기도 한다.

 

따라서 이벤트는 대부분 비동기로 실행되며 그 때 위임되는 함수를 위임함수, 이벤트 함수, 콜백함수 등으로 다양하게 불린다.



화면 처리기술

 

이제 데이터를 가져 왔음으로 그것을 이용하여 화면을 변경할 수 있어야 한다. 그러기 위한 방법은 크게 두 가지로 나뉜다.

 

DOM을 이용한 화면 변경

 

DOM 돔?구장?야구(재영의 말씀)이란 Document Object Model 이란 뜻으로 문서에 있는 객체들을 만들 때 사용하는 형식의 모델을 말하는 말이다.

 

과거에는 문서의 내용을 객체화 할 때 그 형식을 브라우저를 만드는 회사들이 자의적으로 형식을 정의했다면 이제는 그것을 표준화한 Model을 이용하고 있다. 그래서 최근에는 표준 문서 객체를 말할 때 DOM 객체라고 한다.

 

우리는 표준 객체를 이용해서 문서를 조작하게 됨으로써 단일한 환경을 이용한 개발을 할 수 있다.

 

문서 객체 모델은 WWW 컨소시움에서 리딩하던 것이 최근에는 WHATWG에서 리딩하고 있다. 

 

WHATWG란

WHATWG란 Web Application HyperText Technology Working Group이란 뜻으로 과거 HTML4를 이끌던 w3c에서 웹의 새로운 변화(XML을 기반으로 하는 웹)를 꾀하면서 버린 HTML4를 주워와서? ㅜㅜ 새롭게 버전을 붙이고 HTML5를 통해서 새로운 브라우저 기반의 응용프로그램을 만들기 위한 컨소시움을 만든 것이 WhatWG이다.

 

Web Hypertext Application Technology Working Group (WHATWG)

 



지금은 whatwg에서 정의하고 있는 문서 객체 모델을 이용하기 때문에 그것을 활용하는 방법을 이해하려면 whatwg가 적합하겠지만 사실 여기는 스펙만 나올 뿐 실제 구현된 사례가 나오기는 쉽지 않았다. 만약에 실제 구현된 사례를 보려면 MDN 사이트를 통해서 확인하면 쉽게 알아볼 수 있다.



DOM 조작하기

DOM을 조작하려면 가장 먼저 DOM의 객체 종류부터 확인할 수 있어야 한다.

 

DOM은 문서의 모든 객체에 대해서 모델을 제공하고 있기 때문에 태그로 사용되는 모든 것들이 그 형식을 가지고 있다.

 

<!DOCTYPE > 부터 <!-- 주석 --!> 에 이르기 까지 모든 것이 메모리 모델을 가지고 있다. 위의 그림은 그 모델을 이용하여 객체화된 내용의 형식들을 보여주고 있다.

 

<!DOCTYPE>의 객체 형식명은 DocuemntType 이고 textarea, p, font 와 같은 태그들은 Element 객체 형식명을 가지고 있다.

 

이 모든 것들이 문서에 html로 작성된 내용들이고 그 내용이 어떤 형식을 가지고 있는지를 다 암기할 필요는 없다.

 

우리가 암기할 내용은 스크립트로 조작할 대상만 암기하면 된다. 엘리먼트 형식, Text 형식만 이해하면 된다.

 

이 모든 것들은 공통기능을 가지고 있기 때문에 형식들 간의 추상화가 이루어져 있는데 그 모양은 다음과 같다.

 

 

따라서 Node 인터페이스의 기능만 알면 DOM 객체의 공통 기능을 이해할 수 있다고 할 수 있다.

 

Node 인터페이스

Node 인터페이스를 보는 방법은 다음처럼 Node interface MDN을 검색하면 MDN 사이트를 쉽게 찾을 수 있다.

 

 

하지만 이 문서는 좀 방대한 설명이 함께 하므로 인터페이스(기능)만 보기에는 적합하지 않다. 따라서 제일 하단을 보면 다음 과 같은 링크를  볼 수  있다.

 

 

 

위의 링크를 클릭하면 w3c나 whatwg가 제공하는 인터페이스 명세서를 볼 수 있다.

DOM Standard (whatwg.org)

 

이 문서에는 모든 Node가 가지는 공통 속성공통 기능을 볼 수 있다.

 

이 중에서 노드 객체의 종류확인할 때 사용하는 속성으로 다음과 같은 속성이 있다.

이 속성은 노드 타입을 확인하거나 노드 이름을 확인할 때 사용할 수 있고 nodeType에 들어가는 값은 위에 상수를 통해서 확인할 수 있다.



const unsigned short ELEMENT_NODE = 1;
  const unsigned short ATTRIBUTE_NODE = 2;
  const unsigned short TEXT_NODE = 3;
  const unsigned short CDATA_SECTION_NODE = 4;
  const unsigned short ENTITY_REFERENCE_NODE= 5; // legacy
  const unsigned short ENTITY_NODE= 6; // legacy
  const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
  const unsigned short COMMENT_NODE = 8;
  const unsigned short DOCUMENT_NODE = 9;
  const unsigned short DOCUMENT_TYPE_NODE = 10;
  const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
  const unsigned short NOTATION_NODE= 12; // legacy

 

노드 이름도 nodeName을 통해서 확인할 수 있는데 nodeName노드 형식에 따라서 그 이름을 이용하는 방법이 다르다.



 

Element Node 형식인 경우는 nodeName에서 태그 이름을 얻을 수 있지만 

Text Node 형식인 경우에는 #text라는 상수형 문자열만 볼 수 있다. 

반면에 nodeValue 속성을 통해서 Text 내용을 확인할 수 있다.

 

우리는 Element와 Text 노드 객체만 사용할 수 있으면 그것으로 충분하다.



Node 순회를 위한 메소드

노드 인터페이스에는 노드를 순회할 때 사용 할 수 있는 기능으로 다음과 같은 메소드들이 있다.

 

readonly attribute Node? firstChild;
readonly attribute Node? lastChild;
readonly attribute Node? previousSibling;
readonly attribute Node? nextSibling;

 

특정 노드를 선택 한 후에 그 노드 앞에 형제 또는 뒤의 형제를 찾거나 부모 노드나 자식 노드를 찾을 수 있는 속성들을 가지고 있다.

 

 

이 중에서 firstChild는 자식 노드 중에서 첫 번째 자식을 의미하는데, 여기서 주의할 사항이 있다. 그 첫 번째 자식이 엘리먼트만을 대상으로 하지 않는다는 점이다.

 

예를 들어서 다음 예를 보자.

 

<ul id=”list”>

    <li>1</li>

    <li>2</li>

    <li>3</li>

</ul>

 

위의 html 을 통해서 ul dom 객체를 얻어보자.

 

let list = document.getElementById(“list”);

 

그리고 그의 첫 번째 자식인 firstChild를 얻는 코드를 통해서 그 객체를 출력해보자.

 

console.log(list.firstChild) 그럼 어떤 값이 출력 될까?

 

<li>1</li>이 출력될 것이라고 생각하겠지만 사실은 빈 문자열이 출력된다. 왜냐하면 firstChild는 모든 노드를 대상으로 하기 때문에 <ul> 태그가 가지는 첫 째 자식은 다음이 된다.

 

 

 

위의 그림에서 보는 것처럼 빈공백이 Text 노드 객체가 된다. 따라서 우리가 원하는 결과와 다른 노드 객체를 얻을 수 있다. 만약에 주석이라도 달려있다면 주석 객체가 첫 번째 자식이 될 수도 있다.

 

Element vs Node 인터페이스

일반적으로 우리가 얻는 엘리먼트 객체는 사실 HTML Element 객체이다. 이해를 돕기 위해 다음 그림을 보자.

 

 

위의 그림은 HTMLElementElement 인터페이스를 상속하고 있는 것을 볼 수 있다. 우리는 DOM과 HTML DOM으로 구분해볼 필요가 있고 그 둘의 관계는 다음과 같다.

 

 

 

위와 같이 HTMLDOM 객체 인터페이스를 포함하고 있으면서 추가적으로 HTML 들이 가지는 속성들을 확장한 HTMLDOM 인터페이스를 가지고 있다.

 

그래서 그 그림을 좀 더 자세히 그려보면 다음과 같다.

 

 

 

Node를 순회할 때는 모든 Node를 대상으로 하지 않고 Element만을 대상으로 순회할 것이라면 Element의 기능을 이용한 순회를 해야 한다.

 

이 외에도 노드를 순회할 때 사용할 수 있는 도구로는 childNodeschildren 속성이 있다. 둘의 차이는 앞서 설명한 것과 일맥한다. 

Node만을 대상으로 하는 기능은 childNodes 

Element 만을 대상으로 할 때는 children 속성을 사용할 수 있다.

 

만약에 다음과 같은 코드가 있다고 하자.

 

<ul id=”list”><!-- 호호 –>

    <li>1</li>

    <li>2</li>

    <li>3</li>

</ul>

 

위와 같은 코드에서 list.childNodes[0] 를 출력하면 어떤 결과가 나올까?

 

“호호” 일까? <li>1</li> 일까?

 

그렇다 정답은 “호호”이다. 왜냐하면 childNodes는 자식들 모두를 담는 콜렉션이고 그 중에 첫 번째 Node는 주석이기 때문이다. 

하지만 주석이나 테스트 또는 공백을 제외한 엘리먼트만 대상으로 하려고 한다면 다음처럼 코드를 수정해야 한다.

 

list.children[0];

 

그러면 엘리먼트만의 자식들 중에서 첫 번째 자식인 <li>1</li>을 반환하게 한다.

Node 조작을 위한 메소드

Node 인터페이스에는 노드를  수정할 수 있는 기능도 제공하고 있다. 다음 노드가 그 기능을 제공하는 메소드들이다.



 

위의 기능들을 이용하면 노드를 추가,수정,삭제 할 수 있다. 

 

그렇다면 노드를 생성하는 기능은 어떤 메소드인가?

노드를 포함해서 어떤 객체를 생성하는 기능은 오로지 document 만이 가지는 고유 기능이다. 



+

docuement의 능력을 이용해서 

Element 객체를 생성할 때는 createElement(), 

Text 객체를 생성할 때는 createTextNode()를 사용해서 객체들을 생성할 수 있다.

 

객체를 생성하는 기능 외에 객체를 삽입/삭제/추가 하는 기능은 모든 Element 노드 객체가 가지는 기능이다.

 

즉, docuemnt 객체로 생성하고 자신이 삽입을 원하는 객체를 찾아서 그곳에 자식으로 추가하는 방법을 사용할 수 있다.

 

let div = docuemnt.createEleemnt(“div”);



템플릿 문자열을 이용한 화면 변경

(2) 템플릿 문자열을 이용한 화면변경

1)

request.onload = function(){
    let menus = JSON.parse(request.responseText)

    //기존 목록을 모두 지우고
    //menuList.children[0];

    //이게 인덱스 신경안써도 돼서 좋긴하지만, 그래도 위에것이 좋
    menuList.removeChild(menuList.firstElementChild);
    
    //menuList.replaceChildren();

}

children[0] 을 하면 Element 만을 대상으로 하는 것으로서 첫번째 자식객체를 지정가능하다

 

이것 외에도 firstElementChild 로 가능하기도하다

이것의 경우 별도로 지정을 안해서 좋긴하지만 가급적 명확하게 지정이 가능한 children[0] 이 권장된다

 

2)

만약 한번에 클릭할 때 마다 모두 지우고 싶으면

 

request.onload = function(){
    let menus = JSON.parse(request.responseText)

    //기존 목록을 모두 지우고
    //menuList.children[0].remove;

    //이게 인덱스 신경안써도 돼서 좋긴하지만, 그래도 위에것이 좋
    while(menuList.removeChild(menuList.firstElementChild)){
    menuList.removeChild(menuList.firstElementChild);
    }
    //menuList.replaceChildren();

}

반복문으로 가능하다

여기서 removeChile()는 다 지우게 되면 null로서 falsy가 된다.

결국 반복문이 멈추게 되는 방식이다.

 

 


1. 보충

(1)

 

 

2. 회고 

 

'배움 __IL > TIL 1기' 카테고리의 다른 글

TIL : 79번째- 230329 [3-4-수]  (0) 2023.03.29
TIL : 78번째- 230328 [3-4-화]  (1) 2023.03.28
TIL : 76번째- 230324 [3-3-금]  (0) 2023.03.24
TIL : 75번째- 230323 [3-3-목]  (0) 2023.03.23
TIL : 74번째- 230322 [3-3-수]  (0) 2023.03.22