본문 바로가기
  • soldonii's devlog
Javascript 공부/Zero To Mastery(-)

(17) HTTP/JSON/AJAX + 비동기적 자바스크립트 2

by soldonii 2019. 8. 27.

*Udemy의 "The Complete Web Developer in 2019 : Zero To Mastery" 강의에서 학습한 내용을 정리한 포스팅입니다.

*https://soldonii.github.io에서 2019년 7월 29일(월)에 작성한 글을 티스토리로 옮겨온 포스팅입니다.

*자바스크립트를 배우는 단계라 오류가 있을 수 있습니다. 틀린 내용은 댓글로 말씀해주시면 수정하겠습니다. 감사합니다. :)


1. Async Await

앞선 글에서 Promise에 대해서 살펴보았던 Promise를 기반으로 ES8에서 새롭게 추가된 문법이다. Promise와 기본적으로 같은 목적이지만, Promise는 코드가 비동기적으로 작성되어 있다면, Async Await는 비동기적인 동작을 동기적인 문법으로 작성하여 더 코드가 클린해진다.(근데 나는 아직 덜 익숙해서 그런지 Promise로 작성된 문법이 더 읽기 쉬운 것 같기도 하다;)

// promise를 사용한 코드
movePlayer(100, 'Left')
	.then(() => movePlayer(400, 'Left'))
	.then(() => movePlayer(10, 'Right'))
	.then(() => movePlayer(330, 'Left'))

// async await을 사용한 코드
async function playerStart() {
  const firstMove = await movePlayer(100, 'Left'); // pause
  await movePlayer(400, 'Left'); // pause
  await movePlayer(10, 'Right'); // pause
  await movePlayer(330, 'Left'); // pause
}

 

Andrei의 표현을 그대로 옮기면, async await는 Promise와 같은 역할이지만, Promise에 SYNTATIC SUGAR를 더하는 역할이다. async 키워드를 통해 함수를 정의할 수 있고, Promise를 리턴하는 모든 함수 앞에는 await를 사용할 수 있다. 위 사례를 보면, Promise를 사용할 경우 계속 .then()을 이어나가며 체인을 형성하는 비동기적인 코드 작성법을 가질 수 밖에 없는데, async await은 우리에게 익숙한 코드들처럼 동기적으로 코드가 작성되어 있다. 동작은 비동기적으로 동작한다!

 

Promise를 async await으로 다르게 작성한 여러 사례를 살펴보자.

// promise를 사용한 코드
fetch('https://jsonplaceholder.typicode.com/users')
	.then(resp => resp.json())
	.then(console.log)

// async await을 사용한 코드
async function fetchUsers() {
  const resp = await fetch('https://jsonplaceholder.typicode.com/users');
  const data = await resp.json();
  console.log(data);
}
const urls = [
  'https://jsonplaceholder.typicode.com/users',
  'https://jsonplaceholder.typicode.com/posts',
  'https://jsonplaceholder.typicode.com/albums'
]

Promise.all(urls.map(url => {
  return fetch(url)
    .then(resp => resp.json())}))
    .then(results => {
      console.log('users', results[0]);
      console.log('posts', results[1]);
      console.log('albums', results[2]);
    })
    .catch(() => console.log('error'));

//
const getData = async function() {
  const [ users, posts, albums ] = await Promise.all(urls.map(url => 
		fetch(url).then(resp => resp.json())
	))
  console.log('users', users);
	console.log('posts', posts);
	console.log('albums', albums);
}
	/*
	users (10) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
	posts (100) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
	albums (100) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
	*/

 

# async await에서 에러를 잡아내는 방법

Promise의 경우 오류를 잡아낼 때, .then() 체인들 사이에 .catch() 명령어를 사용했었다. async await에서는 try catch blocks 라는 개념을 사용해서 오류를 잡아낸다. 실행할 명령을 try {} 블록 안에 넣고, try {} 블록 내에서 오류가 발생할 경우 어떤 동작을 수행할 것인지를 catch {} 블록 안에 규정해주면 된다. 백문이 불여일견! 아래 코드를 보자.

const urls = [
  'https://jsonplaceholder.typicode.com/users',
  'https://jsonplaceholder.typicode.com/posts',
  'https://jsonplaceholder.typicode.com/albums'
]

// promise에서 .catch()로 에러를 잡아내는 코드
Promise.all(urls.map(url => {
  return fetch(url)
    .then(resp => resp.json())}))
    .then(results => {
      console.log('users', results[0]);
      console.log('posts', results[1]);
      console.log('albums', results[2]);
    })
    .catch(() => console.log('error'));

// async await에서 try, catch로 에러를 잡아내는 코드
const getData = async function () {
  try {
    const [ users, posts, albums ] = await Promise.all(urls.map(url => 
			fetch(url).then(resp => resp.json())
			))
      console.log('users', users);
      console.log('posts', posts);
      console.log('albums', albums);    
  } catch(err) {
    console.log('Oops! Errors!', err);
  }
}

 

2. ES9(ES 2018)

# Object Spread Operator

전개 구문에 대한 설명은 MDN 문서가 이해하기 쉽게 잘 되어 있어서 해당 링크로 대체한다.

Object Spread Operator

const animals = {
  tiger: 23,
  lion: 5,
  monkey: 2,
  bird: 40
}
const { tiger, lion, ...rest } = animals;

console.log(tiger); // 23
console.log(rest); // {monkey: 2, bird: 40}

function objectSpread(p1, p2, p3) {
  console.log(p1);
  console.log(p2);
  console.log(p3);
}

objectSpread(tiger, lion, rest);
/*
23
5
{monkey: 2, bird: 40}
*/

const array = [1,2,3,4,5];
function sum(a,b,c,d,e) {
  return a+b+c+d+e;
}
sum(...array); // 15;

 

3. ES9(ES 2018) - Async

# .finally()

.finally()는 Promise에서 사용되는 명령어다. .then()은 Promise가 resolve 됐을 때 수행할 작업을 정의해줬고, .catch()는 Promise가 reject 됐을 때 수행할 작업을 정의해줬다면, .finally()는 Promise가 resolve되거나, reject되거나 결과에 관계 없이 수행할 작업을 정의할 때 사용된다.

// finally
const urls = [
  'https://swapi.co/api/people/1',
  'https://swapi.co/api/people/2',
  'https://swapi.co/api/people/3',
  'https://swapi.co/api/people/4'
]

Promise.all(urls.map(url => fetch(url)
  .then(people => people.json())
  ))
  .then(array => {
    throw Error;
    console.log('1', array[0]);
    console.log('2', array[1]);
    console.log('3', array[2]);
    console.log('4', array[3]);
  })
  .catch(err => console.log('fix it!', err))
  .finally(() => console.log('extra'));

 

# for await of

Control Flow(조건문)에서 살펴본 내용 중, for of loop이 있었다. for of loop은 iterable한 대상에 대해서 순환하면서 특정 작업을 수행했다면, for await of는 여러 개의 await 명령문들을 순환하면서 특정 작업을 수행토록 할 수 있다.

// for await of
const getData = async function() {
  try {
    const [ users, posts, albums ] = await Promise.all(urls.map(async function(url) {
        const response = await fetch(url);
        return response.json();
    }));
    console.log('users', users);
    console.log('posta', posts);
    console.log('albums', albums);
  } catch (err) {
    console.log('ooooooops', err);
  }
}
// for await of 를 이용해서 변수 data에 Javascript 객체로 parse된 결과물을 넣기
const urls = [
  'https://jsonplaceholder.typicode.com/users',
  'https://jsonplaceholder.typicode.com/posts',
  'https://jsonplaceholder.typicode.com/albums'
]

const getData2 = async function() {
  const arrayOfPromises = urls.map(url => fetch(url));
  for await (let request of arrayOfPromises) {
    const data = await request.json();
    console.log(data);
  }
}

'Javascript 공부 > Zero To Mastery(-)' 카테고리의 다른 글

(19) Node.js와 Express.js 1  (0) 2019.08.27
(18) 백엔드 기본  (0) 2019.08.27
(16) HTTP/JSON/AJAX + 비동기적 자바스크립트 1  (0) 2019.08.27
(15) 리액트  (0) 2019.08.27
(14) NPM + NPM Scripts  (0) 2019.08.27

댓글