배꼽파지 않도록 잘 개발해요

[엘리스sw] 4주차 3일 - async/await, API 본문

교육/엘리스 SW 트랙

[엘리스sw] 4주차 3일 - async/await, API

꼽파 2024. 1. 15. 12:29


◆  async/await
◆  HTTP, REST API
◆  Fetch API


async/await

· Promise를 활용한 비동기 코드를 간결하게 작성하는 문법(syntax sugar)
· async/await 문법으로 비동기 코드를 동기 코드처럼 간결하게 작성할 수 있다.
· async 함수와 await 키워드를 이용한다.

 

async :

  • 함수를 비동기 함수로 만들어 준다.
  • async로 선언된 함수는 반드시 Promise를 리턴한다.

await :

  • 반드시 async 함수 안에서만 사용해야 한다.
  • 해당 줄에서 비동기 작업이 완료될 때까지 코드 실행을 일시 중단한다.

 

· await는 프로미스를 리턴하지 않는 함수라도 사용할 수 있음.
· 단, 이 경우 리턴한 데이터는 Promise.resolve()로 감싸짐.

function nonPromiseFunction() {
  return 'Hello, World!';
}

async function asyncFunction() {
  const result = await nonPromiseFunction();
  console.log(result); // 'Hello, World!'
}

asyncFunction();  // Hello, World!

 

nonPromiseFunction은 프로미스를 반환하는 함수가 아니지만 앞에 await 키워드를 붙여서 사용할 수 있음.
자바스크립트는 nonPromiseFunction의 반환값을 Promise.resolve()로 감싸서 프로미스로 만들어줌.
결과적으로 await는 비동기적으로 실행되지만 마치 동기적으로 코드를 작성한 것처럼 사용할 수 있게 됨.

 

async 함수

· async 함수는 function 키워드 앞에 async를 붙여 만든다.
· async 함수 내부에서 await 키워드를 사용한다.
· fetchData, fetchUser는 Promise를 리턴하는 함수이다.

async function asyncFunc() {
	let data = await fetchdata()
	let user = await fetchUser(data)
	return user
}

 

await 키워드 실행 순서
·  await 키워드는 then 메서드 체인을 연결한 것처럼 순서대로 동작한다.
·  비동기 코드에 쉽게 순서를 부여한다.

async function asyncFunc() {
	let data1 = await fetchData1()
	let data2 = await fetchData2(data1)
	let data3 = await fetchData3(data2)
	return data3
}

function promiseFunc() {
	return fetchData1()
		.then(fetchData2)
		.then(fetchData3)
}

 

에러 처리

·  Promise를 리턴하는 함수의 경우, 에러가 발생하면 catch 메서드를 이용하여 에러를 처리한다.
·  catch 메서드를 사용하지 않는다면 async 함수에서는 try-catch 구문을 이용하여 에러를 처리한다.

·  try-catch 구문으로 async/await 형태 비동기 코드 에러처리가 가능하다.
·  catch 절의 e는 Promise의 catch 메서드가 받는 반환값과 동일하다.

// Promise의 catch 구문

function fetchData1() {
	return request()
		.then((response) => reponse.requestData)
		.catch(error => {
			// error 발생
		})
}
// async 함수 내 try catch 문

async function asyncFunc() {
	try {
		let data1 = await fetchData1()
		return fetchData2(data1)
	} catch (e) {
		console.log("실패:", e)
    }
}

 

Promise 구문와 async/await 구문 비교

항목 callback Promise async/await
가독성 낮음 중간 높음
에러 처리 콜백 헬 발생 가능 .catch()를 통한 처리 try-catch 사용 가능
중첩 처리 콜백 헬 발생 가능 .then() 체이닝 선언적 비동기 코드 구현
let data1 = await fetchData1()
코드 간결성 낮음 보통 높음
동시에 여러 비동기 작업 콜백 헬 발생 가능 복잡한 Promise 체이닝 간단한 병렬처리
메인 스레드 차단 여부 가능 미차단 미차단

 

예시 1

// 비동기적으로 데이터를 가져오는 함수
function fetchData() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('Data fetched!');
    }, 1000);
  });
}

 

Promise 구문

// Promise를 사용한 함수
function fetchDataWithPromise() {
  console.log('Start fetching data...');

  return fetchData()  // fetchData 함수의 프로미스를 반환
    .then((result) => {
      console.log(result);  // 'Data fetched!'
      console.log('End fetching data.');
    })
    .catch((error) => {
      console.error('Error:', error);
    });
}

// fetchDataWithPromise 함수 호출
fetchDataWithPromise();

 

async/await 구문

// async/await를 사용한 함수
async function fetchDataAsync() {
  console.log('Start fetching data...');

  try {
    const result = await fetchData();  // fetchData 함수의 결과를 기다림
    console.log(result);  // 'Data fetched!'
  } catch (error) {
    console.error('Error:', error);
  }

  console.log('End fetching data.');
}

// fetchDataAsync 함수 호출
fetchDataAsync();

 

예시 2

Promise 구문

Promise
    .all([getName(), getAge(), getAddress()])
    .then((res) => {
        const [name, age, address] = res;
        console.log(name, age, address)
    })

Promise.all 메서드를 사용하여 여러 개의 비동기 작업을 병렬로 처리하고, 모든 작업이 완료되었을 때 결과를 합쳐서 처리한다.

 

async/await 구문

(async () => {
    const name = await getName();
    const age = await getAge();
    const address = await getAddress();

    console.log(name, age, address);
})();

getName() 함수가 호출되고, 해당 함수가 프로미스를 반환하면 현재의 실행은 getName() 함수에서 일시 중단된다.
getName() 함수의 프로미스가 완료되면 그 결과가 변수 name에 할당되고, 다음 줄의 코드가 실행된다.

이런 식으로 모든 비동기 작업이 완료되면 console.log(name, age, address);가 실행되어 결과가 출력된다.
이 코드는 각 비동기 작업이 이전 작업의 완료를 기다리기 때문에 순차적으로 실행된다.

 


HTTP, REST API

HTTP(Hypertext Transfer Protocol)
·  web에서 서버와 클라이언트 간의 통신하는 방법을 정한 것
·  클라이언트는 웹 브라우저 등 서버로 요청을 보내는 대상
·  서버는 클라이언트가 요청을 보내기 전까지 대응하지 않음
·  서버와 클라이언트 사이에는 무수히 많은 요소가 존재
→ HTTP는 이런 존재들 사이의 통신 방법을 규정

 

HTTP Message

·  서버 주소, 요청 메서드, 상태 코드, target path, 헤더 정보, 바디 정보 등이 포함됨.

·  요청 메시지, 응답 메시지의 모양이 다름.

·  HTTP/1.1 메시지는 사람이 읽을 수 있으나, HTTP2는 사람이 읽기 불가능함.

출처 : https://developer.mozilla.org/ko/docs/Web/HTTP/Messages

 

HTTP Header

·  HTTP 메시지의 헤더에는 콘텐츠 관련 정보, 인증 관련 정보, 쿠키 정보, 캐시 관련 정보 등 서버와 클라이언트 간 통신 시 필요한 정보를 담는다.
·  클라이언트 요청 시, 서버 응답 시 모두 헤더에 정보를 담을 수 있다.

 

HTTP Status
·  HTTP 요청 시, 클라이언트는 요청의 결과에 대한 상태 정보를 얻는다.
·  200, 400, 500 등 숫자 코드와 OK, NOT FOUND 등의 텍스트로 이루어짐.
·  코드를 이용해 각 결과에 해당하는 행위를 할 수 있음.

 

요청 메서드
·  HTTP에서 클라이언트는 서버로 요청을 보낸다.
·  요청 시 요청 메서드로 특정 요청에 대한 동작을 정의한다.
·  GET, POST, PUT, PATCH, DELETE, OPTIONS, CONNECT, TRACE 등이 규정됨.

  - OPTIONS, CONNECT, TRACE : 브라우저에서 자동으로 처리

  - GET, POST, PUT, PATCH, DELETE : 직접 커스텀해서 사용

  • GET : 리소스 정보를 얻음
  • POST : 리소스를 생성
  • PUT : 리소스를 생성하거나 업데이트
  • DELETE : 리소스를 제거

 

Rest API(Representational State Transfer API)
·  API(Application Programming Interface)는 사용자가 특정 기능을 사용할 수 있도록 제공하는 함수를 의미한다.
·  REST API는 HTTP의 요청 메서드에 응하는 서버 API와 클라이언트 간 통신의 구조가 지켜야 할 좋은 방법을 명시한 것이다.
·  구체적인 내용으로는 요청 메서드의 의미, URI 설계, 클라이언트 상태에 대한 동작 등을 정의한다.


Fetch API

Fetch API

· 기존 XMLHTTPRequest를 대체하는 HTTP 요청 API
· ES6에 추가된 Promise를 리턴하도록 정의됨.
· 네트워크 요청 성공 시, Promise는 Response 객체를 resolve한다.
· 네트워크 요청 실패 시, Promise는 에러를 reject한다.

let result = fetch(serverURL);

result
  .then(response => {
    if (response.ok) {
      // 요청이 성공적으로 이루어졌을 때의 로직
      return response.json(); // JSON 형태의 데이터를 파싱한 Promise를 반환
    } else {
      throw new Error('서버 응답이 성공하지 않음');
    }
  })
  .then(data => {
    // 위에서 반환한 Promise가 이행되면 해당 데이터를 사용하는 로직
    console.log(data);
  })
  .catch(error => {
    // 요청이 실패하거나 응답 처리 중에 에러가 발생했을 때의 로직
    console.error('에러 발생:', error);
  });

 

Response

· Response 객체는 결과에 대한 다양한 정보를 담는다.
· response.ok : HTTP Status code가 200-299 사이면 true, 그 외 false이다.

   ex. 200 "OK", 404 "Not Found", 500 "Internal Server Error"
· response.status : HTTP status code를 담는다.
· response.url : 요청한 URL 정보를 담는다.

fetch(severURL)
	.then(response => {
		response.ok
		response.status
		response.statusText
		response.url	
		repsone.bodyUsed
})

 

Header

·  response.headers로 Response 객체의 헤더 정보를 얻을 수 있다.

fetch(serverURL)
	.then(resp => {
	for (let [k, n] of resp.headers) {
		console.log(k, v)
		}
	})

 

Body

·  response.json() 메서드는 얻어온 body 정보를 json으로 만드는 Promise를 반환한다.
·  Promise가 resolve 되면 얻어온 body 정보를 읽는다.
·  response.text(), response.blob(), response.formData() 등의 메서드로 다른 형태의 바디를 읽는다.

fetch(serverURL)
	.then(response => {
		return reponse.json()
	})
	.then(json => {
		console.log('body : ', json)
	})

 

POST 요청

·  fetch(url, options)로 fetch 메서드 옵션을 넣는다.
·  method 필드로 여러 요청 메서드를 활용한다.
·  headers, body 필드를 활용해 서버에 추가 정보를 보낸다.

fetch(serverURL, {
	method: 'post',
	headers: {
        		'Content-Type':
        		'application/json;charset=utf-8',
        		Authentication: 'mysecret'
		},
			body: JSON.stringify(formData)
		})
		.then(response => {
			return response.json()
		})
		.then(json => {
			console.log('POST 요청 결과:', json)
		})

Axios

  • 웹브라우저와 Node.js를 위한 HTTP 비동기 통신 라이브러리
  • React에서 OpenAPI를 이용한 통신을 할 때 Axios를 주로 사용함.
  • Create : Post - axios.create(url)
  • Read : Get - axios.get(url)
  • Update : Put - axios.put(url, data 객체)
  • Delete: Delete - axios.delete(url)

대부분의 OpenAPI는 PUT요청을 지원하지 않으며, 직접 만들 때 많이 사용함.

Ajax

  • 비동기 자바스크립트, Asynchronous JavaScript and XML
  • 브라우저가 가지고 있는 XMLHttpRequest 객체를 이용하여 화면 전체를 새로 고침 하지 않고 변경된 일부 데이터만 로드
  • fetch : 자바스크립트에 내장
  • Axios : 별도 설치 필요, 호환성 높음, JSON 자동 변환, 응답 시간 초과 설정 기능 등을 지원함.

API

  • Application Programming Interface
  • 운영체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스
  • 프로그램과 프로그램을 연결하는 역할

HTTP

  • Hypertext Transfer Protocol
  • 클라이언트와 서버 간의 규칙
  • 클라이언트의 요청을 HTTP Request, 서버의 응답을 HTTP Response
728x90