Developer Note/국비과정 수업내용 정리&저장

24년 11월 5일

DH_PARK 2024. 11. 11. 01:02

오전

동기 비동기 ?

비동기 처리로 하는 작업.

ajax ? axios ? 를 사용해서 하는 비동기 작업 처리.

 

AJAX  란

둘 다 라이브러리는 아니고 AJAX 란 Asynchronous JavaScript and XML의 약자로

자바스크립트와 xml 을 이용한 비동기적 정보 교환 기법이다.

요새는 xml보다는 json을 주로 사용한다고 함.


동기 , 비동기란 ?

  • 동기
    • 직렬적 방식으로 태스크를 수행하는 방식이다.
    • 요청을 보낸 후 응답을 받아야 다음 동작이 이루어지는 방식이다.
    • 어떠한 태스크를 처리할 동안 나머지 태스크는 대기한다.
    • 실제 성능이 저하되는건 아니지만 , 시스템의 전체적인 효율이 저하된다.
  • 비동기
    • 병렬적 방식으로 태스크를 수행하는 방식
    • 요청의 응답 수락 여부와는 상관없이 다음 태스크가 동작하는 방식이다. 예)a 태스크가 실행한다고 하면 a 와 관계없이 b 태스크를 실행할 수 있으므로 자원을 효율적으로 사용할 수 있다.
    • 너무 많은 비동기 요청을 처리할 시 콜백함수가 중첩되어 복잡도가 높아지는 “콜백 헬” 이 발생하는 단점이 있다. ****
    • 비동기 요청시 응답 후 처리할 ‘콜백 함수’를 함께 알려준다. 그래서 해당 태스크가 완료되면 콜백함수가 호출된다.
    간단히 생각해서 , 웬만한 웹사이트에서는 비동기 방식을 사용하는 웹사이트가 대부분이다. 한 페이지 안에서 많은 서비스를 실행해야 하기 때문에 비동기 방식을 쓸 수 밖에 없다.

비동기 장점 , 단점

  • 여러 요청을 동시에 처리한다는게 가장 큰 장점. 웹페이지에서 파일을 다운한다고 가정했을 때 그동안 다른 서비스를 이용할 수 있는게 바로 “비동기방식” 이다.
  • 그러나 너무 많은 요청이 들어와버리면 시스템이 엄청 복잡해진다는게 문제다.

동기 장점 , 단점

  • 코드가 작성 순서대로 실행되기 때문에 흐름을 이해하기 쉽다.
  • 고로 작업 진행순서가 먼저 실행된 작업 다음에 반드시 다음 작업이 실행된다.
  • 유지보수가 간단해짐.
  • 한줄 씩 실행되기 때문에 에러를 금방 파악할 수 있다.
  • 초보 개발자들이 단순한 프로그램을 만들때 직관성을 높기 때문에 작업난이도를 낮출 수 있다.

콜백지옥(헬)의 예

비동기의 단점. 잘못하면 이런식으로 무한으로 겹겹이 쌓인 콜백함수를 실행하게 될 지도 모른다.

그래서 어떻게 사용하나 ?

우선 라이브러리를 수동으로 추가해줘야함.

수업에서는 axios 라는 라이브러리를 사용해서 비동기방식을 처리했다.

axios 외에는 Promise 라는 객체로 비동기 작업을 처리할 수 있다.

Axios 란 ?

브라우저 , Node.js 를 위한 Promse API를 활용하는 HTTP 비동기 통신 라이브러리이다.

  • 쉽게 말해서 백엔드랑 프론트엔드랑 통신을 쉽게하기 위해 Ajax와 더불어 사용한다.
  • 이미 자바스크립트에는 fetch api가 있지만, 이라고 보면 된다.사용을 위해서 axios cdn 을 link 받아서 사용
  • 프레임워크에서 ajax를 구현할땐 axios를 쓰는 편

자바스크립트 내장라이브러리인 fetch 가 있지만 확장성을 위해 axios 를 많이 사용한다고 한다.

Axios 문법

axios({
	url: '<https://test/api/cafe/list/today>', //통신할 웹문서
		method : 'get',//통신할 방식
	data : {         //인자로 보낼 데이터
		ftt: 'diary'
	}
});

프로필 사진 업로드 코드

//이미지 업로드 버튼 클릭 이벤트
profileUploadBtn.addEventListener("click",function(e){
	
	console.log("profileUploadBtn clicked..");
	
	
	//post('url','param','header-type')
	axios
	.post(  //서버에 post 요청을 보내는 함수
		path+'/user/profile/upload' , //요청 URL
		formData,  //서버로 전송할 데이터
		{ headers:{'Content-Type' :'multipart/form-data'} } //요청 헤더
	)
	.then(resp=>{ console.log(resp); })  //성공시 실행되는 코드
	.catch(err=>{ console.log(err); } )  //실패시 실행되는 코드
	
	
});

댓글 추가 코드

/**
 * 
 */

console.log('read.js...');

const replyAddBtn = document.querySelector(".reply-add-btn");  //댓글 추가 버튼 선언
replyAddBtn.addEventListener('click',function(){  //버튼을 클릭할 시에 발생하는 이벤트 처리
	console.log("replyAddBtn clicked..");
	
	const contents =document.querySelector('.reply-header textarea').value;  //텍스트 박스안에 내용을 불러옴
	
	axios.get( `${path}/book/reply/add?bookCode=${bookCode}&contents=${contents}`)  //get 요청을 사용하여 서버에 데이터를 요청
	.then(     //요청을 성공적으로 처리한 경우 실행되는 코드 블록
		resp=>{  
			
			//기존 노드 삭제
			const parentNode = document.querySelector('.reply-box');  //reply-box라는 클래스의 태그를 찾음
			while(parentNode.firstChild){                              //첫번째 요소가 삭제되게 함
				parentNode.removeChild(parentNode.firstChild);
			}
			
			console.log(resp);
			document.querySelector('.reply-header textarea').value="";  //댓글 입력창의 내용을 빈 내용으로 만듬
			
			//받아와서 표시하기
			receiveReplyData(`${bookCode}`);   //사용자가 새로 입력한 데이터를 화면에 표시한다
		})
	.catch(error=>{console.log(error);})
	
//	createReplyItem();
})

let i = 0;

const createReplyItem = (item) => {    //새로운 댓글 박스를 만드는 함수
    const parentNode = document.querySelector('.reply-box');   
    
    console.log("Reply item created...");

    // 새로운 reply 아이템을 위한 div 생성
    const itemDiv = document.createElement('div');
    itemDiv.className = 'item';   //item 이라는 class 이름의 div 요소 생성
    
    // 아이템의 왼쪽 영역 생성
    const leftDiv = document.createElement('div');
    leftDiv.className = 'left';

    const profileImg = document.createElement('img');   
    profileImg.src = `${path}/profile/image?username=${item.username}`;   //프로필 사진의 경로
    profileImg.alt = 'profileImage';  //이미지 로드할 수 없는경우 대체 텍스트 지정

    const usernameDiv = document.createElement('div');  //댓글창에서 username을 나타낼 div 생성
    usernameDiv.textContent = item.username;  

    leftDiv.appendChild(profileImg);   //왼쪽 div 태그에 프로필이미지와 아래에 usernameDiv 생성
    leftDiv.appendChild(usernameDiv);

    // 아이템의 오른쪽 영역 생성
    const rightDiv = document.createElement('div');
    rightDiv.className = 'right';

    const dateDiv = document.createElement('div');    // 생성 시간에 관한 박스 생성
    dateDiv.className = 'date';
    dateDiv.textContent = item.createAt;

    const contentDiv = document.createElement('div');  //내용에 관한 박스 생성
    contentDiv.className = 'content';

    const textarea = document.createElement('textarea');
	textarea.classname ="form-control";
    textarea.cols = 10;
    textarea.rows = 2;
    textarea.readOnly = true;
    textarea.textContent = item.contents;

    contentDiv.appendChild(textarea);

    // 버튼 그룹 생성
    const buttonGroupDiv = document.createElement('div');
    buttonGroupDiv.className = 'buttongroup';

    const thumbUpSpan = document.createElement('span');
    thumbUpSpan.className = 'material-symbols-outlined';
    thumbUpSpan.textContent = 'thumb_up';

    const thumbDownSpan = document.createElement('span');
    thumbDownSpan.className = 'material-symbols-outlined';
    thumbDownSpan.textContent = 'thumb_down';

    buttonGroupDiv.appendChild(thumbUpSpan);
    buttonGroupDiv.appendChild(thumbDownSpan);

    // 오른쪽 영역에 date, content, 버튼 그룹 추가
    rightDiv.appendChild(dateDiv);
    rightDiv.appendChild(contentDiv);
    rightDiv.appendChild(buttonGroupDiv);

    // 전체 아이템에 왼쪽과 오른쪽 영역 추가
    itemDiv.appendChild(leftDiv);
    itemDiv.appendChild(rightDiv);

    // parentNode에 itemDiv 추가
    parentNode.appendChild(itemDiv);
	
	
	
}
	
	
	const receiveReplyData  = (bookCode)=>{
		console.log(path,bookCode);
		
		axios.get(`${path}/book/reply/list?bookCode=${bookCode}`)  //위에 axios 함수에서 이 함수가 실행되면 똑같이 get방식으로 서버에 요청을 보낸다.
		.then(
			resp=>{
				console.log(resp.data);//true일 때
				resp.data.forEach(el=>{
					createReplyItem(el);
				})
				
			})
		.catch(error=>{console.log(error);}) //에러일 때
	}

	receiveReplyData(`${bookCode}`);

동작 순서

여기서 댓글 추가 버튼을 누르면 get 으로 서버에 요청을 보내는데 이 때 frontController 에서 요청을 받아서 각자의 subController 로 매핑을 해준다.

그러면 ReplyAddController 에서 replyAdd 서비스로직을 실행해서 dao까지 접근해 , 데이터를 만든다.

그 후에 아래 JS 함수 receiveReplyData () 함수를 실행해서 reply/list 엔드포인트로 접근 .

frontcontroller 에서 다시 reply/list 에 있는 subController 로 전달한다.

			ObjectMapper mapper = new ObjectMapper();
			mapper.registerModule(new JavaTimeModule());		//
			String jsonData = mapper.writeValueAsString(list);
			// 뷰로이동(내용전달 - ?)
					PrintWriter out = resp.getWriter();
			out.println(jsonData);

그러면 ReplyListController 에서 받은 데이터를 JSON 타입으로 변환시켜 다시 리턴한다.

그러면 이 받은 데이터를 사용해서 js함수에서 댓글정보가 있는 DIV 태그를 생성하게 된다. 그리고 다시

receiveReplyData 함수에서 createReplyItem 함수를 실행해서 댓글내용이 있는 div를 생성후 전체적인 댓글 목록을 나타내게 된다.

그러면 이게 비동기 요청과 어떤 연관이 있는가 ?

axios.get 은 서버에 HTTP 요청을 비동기로 보낸다.

그러면 페이지에서는 새로고침을 따로 하지않고 서버의 응답을 처리하게 되는데 , 이 때 비동기요청이기 때문에 사용자는 다른작업을 계속해서 수행할 수 있게 된다. (비동기방식의 장점 ! ) ex)사용자 입력 처리

비동기 요청이 완료되면 .then 안의 코드블럭이 실행되게 되는데 , 이 때 만약 동기방식이라면 전체페이지를 새로고침하게 되는데 , 비동기방식이라면 새로고침 없이 필요한 데이터만 서버에서 받아와 화면을 업데이트 할 수 있다.

※ 새로고침이 되는 이유는 기본적으로 HTML 태그에서 form 요소가 서버로 데이터를 전송하면 페이지를 새로고침하게 된다고 한다.

(전체 페이지를 다시 렌더링 하게된다 ! )


비동기 방식은 웹 백엔드 개발자로서는 무조건 알아야할 기술이기 때문에 시간을 더 내서라도 이렇게 세세하게 공부해보았다.

사용자 입장에서는 정말 아무것도 아닌 작업같지만 이렇게 직접 알아보니 정말 많은 코드와 기술이 들어가게 된다는걸 알았다.

'Developer Note > 국비과정 수업내용 정리&저장' 카테고리의 다른 글

24년 11월 06일  (0) 2024.11.20
24년 11월 7일  (0) 2024.11.19
24년 11월 4일  (4) 2024.11.06
24년 11월 1일  (3) 2024.11.05
24년 10월 31일  (1) 2024.11.04