비동기 프로그래밍 ( feat. Ajax, JSON, XMLHttpRequest)

taehyung·2024년 5월 15일
0

JavaScript

목록 보기
10/15

비동기 프로그래밍은 왜 필요할까 ❓❓

자바스크립트 엔진은 단 하나의 실행 컨텍스트 ( 이하 콜 스택 )를 가지며, 콜 스택은 자바스크립트가 종료될 때까지 유지되면서 Task를 처리한다. 이는 자바스크립트가 싱글스레드 언어라는 것을 확실히 표현하고 있는 것이다.

//sleep 함수는 현재시간 + delay 후에 callback() 함수를 실행한다.
function sleep(sec) {
    let start = Date.now(), end = start;
  
    while (end - start < sec * 1000) {
        end = Date.now();
    }
}

console.log('첫번째');
sleep(3);
console.log('두번째?');

이 코드의 sleep 함수는 실행하면 3초 동안 콜 스택에서 계속 실행되는데, console에 "두 번째?'라는 텍스트가 출력되기까지 3초나 걸린다는 뜻이다.

자바스크립트는 싱글스레드로 동작하여 한 번에 하나의 일밖에 처리하지 못하는데, 처리하는 데 시간이 걸리는 태스크를 실행하는 경우 블로킹( 작업 중단 ) 현상이 발생한다.

위와 같은 경우는 3초 정도의 블로킹이 발생했지만, 실수로 무한 루프에 빠져본 경험이 있다면 알 것이다. 얼마 가지 않아 브라우저가 종료된다는 것을.

이렇게 시간이 걸리는 작업들로 인해 사용자 경험이 저하되는 것을 방지하기 위해 비동기 프로그래밍이 시작되었다.


비동기 프로그래밍의 작동 원리

블로킹을 방지하려면 어떻게 해야할까?
자바스크립트의 비동기 코드 작동 원리는 간단하다. 자바스크립트 엔진은 싱글스레드로 작동하기 때문에 한 번에 한 가지 일만 처리할 수 있지만, 태스크를 잠시 치워두고 나중에 다시 이어나가거나, 또는 다른 작업자에게 맡길 수 있다.


위 그림은 자바스크립트 엔진과 브라우저에서 비동기 코드를 처리하는 방법을 표현한것이다.

대표적인 비동기 함수인 타이머 함수로 예를 들어보자.

function a(){
	console.log('a')
}

function b(){
	console.log('b')
}

setTimeout(a,0); //최소 지연시간 4ms
b();

//결과
b
a

왜 a 보다 b가 먼저 출력되었을까?

function a(){
	console.log('a')
}

function b(){
  	setTimeout(a,0); //코드를 이렇게 바꿔보면 ?
	console.log('b')
}

b();

//결과
b
a

코드를 이렇게 변경해도 결과는 같다. 그 이유는

  1. 비동기로 작동하는 코드는 실행 컨텍스트가 활성화되면 비동기 코드를 호출 스케줄링하고 그 즉시 실행을 종료한다.
  2. 호출 스케줄링 된 비동기 코드는 그 종류에 따라 태스크 큐, 마이크로 태스크 큐로 이동한다.
  3. 콜 스택의 모든 태스크가 처리된 후 ( 동기 코드 종료 후 ) 비동기 코드들의 실행 컨텍스트가 이벤트 루프에 의해 콜 스택에 푸시 된다.

즉, 모든 동기 코드가 종료된 후에야 비동기 코드가 하나씩 실행된다는 것이다.

주의해야 할 점은 싱글스레드 방식으로 동작하는 것은 자바스크립트 엔진뿐이다. 브라우저는 멀티스레드란 말이다. 만약 모든 자바스크립트 코드가 자바스크립트 엔진에 의해 실행된다면 자바스크립트는 비동기로 동작할 수 없다. 이처럼 자바스크립트와 브라우저는 매우 밀접한 관계를 가지고 있다.

요약

비동기를 사용하는 이유
작업시간이 긴 태스크가 콜스택에서 블로킹을 발생시키는것을 막기위해

비동기의 작동 원리
비동기 코드의 실행 컨텍스트 열림 -> 태스크 큐로 이동 -> 비동기 코드 실행 컨텍스트 종료 -> 다음코드 블럭들 진행


매크로 태스크 큐 와 마이크로 태스크 큐

JavaScript는 여러 종류의 콜백 큐를 가지고 있지만 그중 가장 중요한 두 가지 큐에 대해 알아보기로 한다.

큐(queue)는 데이터를 저장하는 자료 구조로, 데이터가 선입선출(FIFO, First-In-First-Out)의 원칙에 따라 처리된다. 이것은 일종의 대기열로 생각할 수 있는데, 가장 먼저 들어온 데이터가 가장 먼저 처리되고 나중에 들어온 데이터는 그다음에 처리되는 방식을 말한다.

콜 스택과는 반대되는 개념이다.

두 큐는 JavaScript의 비동기 코드들을 담고 있는 대기열로 우선순위가 있으며, 마이크로 태스크 큐가 더 우선적으로 실행되고 비워진다.

매크로 태스크 큐 ( 태크스 큐 )
주로 브라우저나 Node.js와 같은 호스트 환경에서 제공되는 비동기 함수들의 대기열이다. 예를 들어, setTimeout, setInterval, 이벤트 핸들러 (예: 클릭, 키보드 입력 등) 등이 여기에서 대기한다. 이러한 함수들은 비교적 더 무거운 작업을 수행하거나 시간이 오래 걸리는 작업을 처리ㅘ녀. 이들 작업은 콜 스택이 완전히 비어있을 때 실행된다.

마이크로 태스크 큐
주로 프로미스와 관련된 작업이 대기한다. 프로미스의 then() 메서드나 catch() 메서드와 같은 콜백 함수들이 여기에 포함되며. 마이크로 태스크 큐에 들어간 작업은 매크로 태스크보다 우선순위가 높아서, 현재 실행 중인 코드가 종료되면 바로 실행된다. 이렇게 함으로써 프로미스 체이닝과 관련된 작업들이 가능한 한 빠르게 처리될 수 있다.


Ajax ( Asynchronous JavaScript and XML )

Ajax란 자바스크립트를 사용하여 브라우저가 서버에게 비동기 방식으로 데이터를 요청하고, 서버가 응답한 데이터를 수신하여 웹페이지를 동적으로 갱신하는 프로그래밍 방식을 말한다.

브라우저의 API 인 XMLHttpRequest 객체를 기반으로 동작하며, 웹 페이지의 일부분만을 동적으로 변경할 수 있게되었다.

기존 방식의 단점
1. 페이지에 변경이 필요하지 않은 부분도 변경하여 불필요한 통신에 비용이 발생한다.
2. 페이지 전체를 렌더링하기 때문에 화면에 깜빡임이 발생한다.
3. 클라이언트와 서버의 통신이 동기 방식이기때문에 서버로부터 응답이 있을때까지 다음 처리는 블로킹된다.

Ajax 통신의 장점
1. 페이지에 변경이 필요한 부분만 서버와 통신하여 불필요한 통신에 비용이 발생하지 않는다.
2. 페이지 전제를 렌더링하지 않기 때문에 화면에 깜빡임이 발생하지 않는다.
3. 클라이언트와 서버의 통신 방식이 비동기로 동작하기 때문에 블로킹이 발생하지 않는다.


JSON ( JavaScript Object Notation )

JSON 이란 클라이언트와 서버의 HTTP 통신을 위한 텍스트 데이터 포맷이다. JavaScript 객체 리터럴과 유사한 형태로 키와 값으로 구성된 텍스트이다.

{
	"name":"kim",
    "age":30,
}

클라이언트에서 서버로 데이터를 보낼 때 ( 직렬화 )

JSON.stringify() : JavaScript 객체, 배열을 JSON 포맷으로 변환한다. JSON은 텍스트라고 하였다. 즉, JavaScript 객체를 JSON 이라는 형태의 텍스트로 변경하는것. 클라이언트가 서버로 객체,배열을 전송하려면 이를 문자열로 변환해야하는데 이것을 직렬화라고한다. (serializing)

서버에서 클라이언트로 데이터를 보낼 때 ( 역직렬화 )

JSON.parse() : JSON 포맷을 Javascript 객체, 배열으로 변환한다. 서버에서 클라이언트로 전송된 JSON 문자열을 JavaScript에서 사용하기 위해서는 문자열을 객체화 해야하는데 이것을 역직렬화라고한다. (deserializing)

클라이언트와 서버 간의 양방향 통신에서 데이터란 문자열로 변환되어야 하고, 받은 쪽에서는 다시 원래 형태로 돌려서 사용해야 하는것 뿐..


XMLHttpRequest

브라우저에서 HTTP 요청을 전송하는 기본적으로 제공된 방법에는

  1. 주소창에 주소를 입력
  2. a 태그
  3. form 의 submit

세 종류가 있으며, Web API의 XMLHttpRequest 객체를 사용한다. 그 외의 요청은 개발자의 의도대로 개발하는 것이다.

XMLHttpRequest 객체는 Http 통신의 송수신을 위해 다양한 프로퍼티와 메서드를 제공한다.

XMLHttpRequest 객체의 프로토타입 프로퍼티설명
readyStateHTTP 요청의 현재 상태를 나타내는 정수로 정적 프로퍼티를 값으로 갖는다.
⚪️ UNSET : 0 ( open 메서드 호출 이전 )
⚪️ OPENED : 1 ( open 메서드 호출 이후 )
⚪️ HEADERS_RECEIVED : 2 ( send 메서드 호출 이후 )
⚪️ LOADING : 3 ( 서버 응답중 )
⚪️ DONE : 4 ( 서버 응답 완료 )
statusHTTP 요청에 대한 응답 상태( HTTP 상태코드 )를 나타내는 정수
⚪️ 100 번대 ( 정보 응답 ) : 요청에 대한 정보를 응답
⚪️ 200 번대 ( 성공 응답 ) : 요청에 대한 성공을 의미하는 200 번대 메시지
⚪️ 300 번대 ( 리다이렉션 메시지 ) : 요청한 리소스에 대한 주소 변경이 있음을 알려주는 응답
⚪️ 400 번대 ( 클라이언트 에러 응답 ) : 클라이언트가 잘못된 요청을 했을 때의 응답
⚪️ 500 번대 ( 서버 에러 응답 ) : 요청에대한 처리를 서버에서 할 수 없을 때의 응답
statusTextHTTP 요청에 대한 응답 메시지를 나타내는 문자열
⚪️ ex ) 'OK'
responseTypeHTTP 응답 타입
⚪️ ex ) document, json, text, blob, arraybuffer
responseHTTP 요청에 대한 응답 바디 (response body) 응답 타입에 따라 달라진다.
responseText서버가 전송한 HTTP 요청에 대한 응답 문자열

XMLHttpRequest 객체의 이벤트 핸들러 프로퍼티설명
onreadystatechangereadyState 속성이 변경될 때마다 발생
onloadstart요청에 대한 응답을 받기 시작할 때 발생
onprogress요청의 진행 상황을 추적 ( 주기적으로 발생 )
onabortabort 메서드를 사용하여 요청을 중단할 때 발생
onerror요청이 실패했을 때 발생
onload요청이 성공적으로 완료됐을 때 발생
ontimeout요청 시간이 초과됐을 때 발생
onloadend요청이 완료된 후 성패여부에 관계없이 발생

XMLHttpRequest 객체의 이벤트 메서드설명
open(method, url, async, username, password)HTTP 요청을 초기화하고 서버에 보낼 메서드, URL 및 비동기 여부를 설정
send(body)HTTP 요청 전송
abort()현재 전송된 HTTP 요청 취소
setRequestHeader(header, value)특정 HTTP 요청 헤더 값 설정
getResponseHeader(header)특정 HTTP 응답 헤더 값을 문자열로 반환

HTTP 요청 전송

HTTP 요청을 전송하는 경우 다음 순서를 따른다.

  1. HTTP 요청을 초기화한다.
  2. 필요에 따라 HTTP 요청의 헤더 값을 설정한다.
  3. HTTP 요청을 전송한다.
const xhr = new XMLHttpRequest(); // XMLHttpRequest 인스턴스 생성
xhr.open('GET','/users'); // 요청 초기화
xhr.setRequestHeader('content-type','application/json'); // 헤더 설정
xhr.send(); // 요청 전송 기본값 : 비동기 요청

서버로 데이터를 보낼 때는

  • get,delete : URL에 쿼리스트링, URL파라미터를 이용하여 전송한다.
  • post,put,patch : 요청 body에 페이로드를 담아 전송한다.
xhr.send(JSON.stringify({id:1,username:'kim'})); // 페이로드는 send 메서드로 전송한다. 

다음 포스팅에는 REST API 에 대해 작성합니다.

profile
Front End

0개의 댓글