Elice SW engineer - TIL day 18, 19

Circlewee·2022년 4월 28일
0

Elice SW 2 TIL

목록 보기
16/31

1. async/await

  • Promise를 활용한 비동기 코드를 간결하게 작성하는 문법(syntactic sugar)
  • async로 선언된 함수는 반드시 Promise를 리턴한다.
  • 하지만 비동기적인 처리를 원한다면 then을 사용해야함
async function asyncFunc() {
  	let data = await fetchData();
  	let user = await 
  		fetchUser(data) {
  	  		return user
        }
}

1.1 작성 방법

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)
}
  • 두개의 함수의 작동은 동일하게 순서대로 동작한다. (순서가 생김)
  • await 키워드는 반드시 async 함수 안에서만 사용해야 한다.

1.2 진행 방식

  1. promise 는 미래 결과값에 대한 약속임
  2. await를 통해 promise의 결과값인 response를 기다림
  3. await가 없으면 promise(약속)만 저장
  4. await가 있으면 response(약속의 결과)가 저장

1.3 예외처리

async function asyncFunc() {
  	try {
    	let data1 = await fetchData1();
      	return fetchData2(data1);
    } catch (e) {
      	console.log('실패: ", e)
    }
}
  • catch()를 통해 에러를 처리하던 Promise처럼 async/await도 try-catch 구문을 이용하여 에러를 처리할 수 있다. 이때 catch 절의 e는 promise의 catch 메서드가 받는 반환 값과 동일하다.
  • 각각의 경우에 대한 에러처리를 하고 싶으면 try 구문 안에 있는 코드를 나누면 된다.

실행시간을 직접 확인할 수 있는 방법

// ...의 실행 시간을 알 수 있다. value는 원하는 값을 넣어도 되지만 시작과 끝은 같아야한다.
console.time(value);
...
console.timeEnd(value);

2. HTTP, REST API

2.1 HTTP

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

2.1.1 HTTP message

  • 서버 주소, 요청 메서드, 상태 코드, target path, 헤더 정보, 바디 정보 등이 포함된 메시지

  • 요청메시지 응답 메시지의 모양이 다르고 HTTP/1.1 메시지는 사람이 읽을 수 있음(읽을 수 없는 메시지도 존재)

  • message header
    1. 컨텐츠 관련 정보, 인증 관련 정보, 쿠키 정보, 캐시 관련 정보등 서버와 클라이언트 간 통신 시 필요한 정보를 담는다.
    2. 클라이언트 요청 시, 서버 응답 시 모두 헤더에 정보를 담을 수 있다.

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

  • 요청 메소드
    1. 클라이언트가 서버로 보내는 요청 시 요청 메소드로 특정 요청에 대한 동작을 정의한다.
    GET, POST, PUT, PATCH, DELETE, (OPTIONS, CONNECT, TRACE)등이 규정됨
    ()는 브라우저에서 자동으로 처리해줌

    2.2 REST API

  • Representational State Transfer API

  • REST API는 HTTP의 요청 메소드에 응하는 서버 API와 클라이언트 간 통신의 구조가 지켜야 할 좋은 방법을 명시한 것이다.

  • 요청 메서드의 의미, URI 설계, 클라이언트의 상태에 대한 동작등을 정의

    3. fetch

fetch(serverURL)
	.then(response => {
  		response.ok
  		response.status
  		response.statusText
  		response.url
  		response.bodyUsed
	})
  1. response.ok: HTTP Status code가 200-299 사이면 true, 그 외 false
  2. response.status: HTTP status code를 담는다.
  3. response.url: 요청한 URL 정보를 담는다.
fetch(serverURL)
	.then(response => {
		for (let [k, v] of response.headers) {
        	console.log(k, v);
        }
	})
  1. response.headers: Response 객체의 헤더 정보를 얻을 수 있다.
fetch(serverURL)
	.then(response => response.json())
	.then(json => {
  		console.log('body : ', json);
	})
  1. response.json: 얻어온 body 정보를 json으로 만드는 Promise를 반환한다.
    Promise가 resolve되면 얻어온 body정보를 읽는다.
    response.text, response.blob, response.formData등의 메소드로 각자 다른 형태의 바디를 읽을 수 있다.

실습 5 Post 정보 조합하기

// api.js
const API_URL = "https://jsonplaceholder.typicode.com";

const fetchPosts = () =>
  fetch(`${API_URL}/posts`).then((response) => response.json());

const fetchUsers = () =>
  fetch(`${API_URL}/users`).then((response) => response.json());

const fetchComments = (postId) =>
  fetch(`${API_URL}/posts/${postId}/comments`).then((response) =>
    response.json()
  );

export default { fetchPosts, fetchUsers, fetchComments };
  • api.js에서 데이터를 fetch해 Promise 객체로 반환한다.
// Posts.js
import API from "./api";

const requestPosts = () => {
  // 데이터를 적절하게 조합하여 Post 정보를 만들어보세요.
  return Promise.all([
    API.fetchPosts(),
    API.fetchUsers()
  ])
    .then(([ posts, users ]) => {
      return fetchCommentsByPosts(posts)
        .then(comments => [ posts, users, comments ]) // comment가 붙은 posts
    })
    .then(([ posts, users, comments ]) => {
      const userMap = createUserMap(users)
      const commentMap = createCommentMap(comments)
      
      return transformPosts(posts, userMap, commentMap);
    })
};

function createUserMap(users) {
  return users.reduce((map, user) => {
    map[user.id] = user
    return map
  }, {})
}

function createCommentMap(comments) {
  return comments.reduce((map, comment) => {
    const array = map[comment.postId] ? map[comment.postId] : []
    array.push(comment)
    map[comment.postId] = array
    return map
  }, {})
}

function fetchCommentsByPosts(posts) {
  return Promise.all(
    // API.fetchComments를 통해 Promise 객체의 배열을 담은 배열을 만듬
    posts.map(post => API.fetchComments(post.id))
  )
  	// 위에서 map 메소드로 인해 2차원 배열이 됐으므로 flatMap으로 1차원 배열로 만듬
    .then(commentArray => commentArray.flatMap(array => array))
}

function transformPosts(posts, userMap, commentMap) {
  return posts.map(({id, userId, ...rest}) => 
    ({
      ...rest, 
      user: userMap[userId],
      comments: commentMap[id]
    }))
//     // const postComments = comments
//     //   .filter(comment => comment.postId === post.id)
//     const postComments = commentMap[post.id]
          
//     post.comments = postComments
          
//     if (userMap[post.userId]) {
//       post.user = userMap[post.userId];
//     }
//     return post;
//   });
}

export default requestPosts;

requestPosts

  1. Promise.all()을 통해 API.fetchPosts().resolve()와 API.fetchUsers().resolve()를 배열의 형태로 만든다.

  2. 첫 번째 then에선 1에서 전달받은 Promise 객체의 배열에 각각 posts, users라는 이름을 붙이고 fetchCommentsByPosts()함수를 호출한다. 그 후 반환 값에 then을 연결해 [posts, users, comments]라는 배열을 Promise 객체의 형태로 반환하게 한다.

    2-1. fetchCommentsByPosts(posts)에서는 posts를 인자로 받아 API.fetchComments를 통해 post.id에 해당하는 comment배열을 Promise객체로 감싼 후 그것을 담은 배열을 만듬. 여기서 그냥 반환하면 2차원 배열을 반환하게 되므로 flatMap()을 통해 1차원 배열로 반환

  3. 두 번째 then에선 [posts, users, comments]를 받아 userMap과 commentMap을 만들고 transformPost()에 인자로 넘긴다.

  4. posts를 map으로 순회하면서 user와 comments를 매칭한 배열을 결과값으로 반환한다.(Promise 객체 형태)

profile
공부할 게 너무 많아요

0개의 댓글

관련 채용 정보