대가는 결과를 만든다

async & await을 정리해보자 (ECMA 2017) 본문

개발/Javascript

async & await을 정리해보자 (ECMA 2017)

yunzema 2020. 3. 16. 15:52
반응형

ES6(ECMA2015) Promise를 좀 더 편하게 사용하기 위한 것으로 ES8(ECMA 2017)에서 발표된 문법이다.

async await에 대해 정리해본다.


1. asyncfunction 앞에 위치 한다.

2. async를 function 앞에 붙이면 해당 함수는 항상 Promise륻 return한다.

  (항상 resolved promise로 값을 감싸 반환되도록 한다.)

async function f() {
  return 1;
}

f().then(alert); // 1

// 혹은 명시적으로 promise를 return (위와 동일)
async function f() {
  return Promise.resolve(1);
}

f().then(alert); // 1

3. awaitasync함수 안에서만 동작한다.

4. await 키워드는 promise가 처리(settled)될 때까지 기다린다.

async function f() {

  //1초 후 실행 완료되는 promise 함수
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("완료!"), 1000)
  });

  let result = await promise; 	// 프라미스가 이행될 때까지 기다림 (*)

  alert(result); 		// 1초 뒤 "완료!"를 출력. 위에서 기다리지 않았다면 아무것도 출력하지 않았을 것!
}

f();

=> 기다렸다가 프로미스가 처리되면 그 결과와 함께 실행이 재개된다. 프로미스가 처리되길 기다리는 동안 엔진이 다른 일을 할 수 있기 때문에, CPU 리소스 낭비되지 않는다.

 

5. awaitpromise.then보다 가독성을 개선하고 쉽게 쓸 수 있도록 한 문법이다.

//기존 promise 이용 문법
function showAvatar(){
	return new Promise(function (resolve, reject) {
    	let img = document.createElement('img');
    	img.src = githubUser.avatar_url;
    	img.className = "promise-avatar-example";
    	document.body.append(img);
    
    	setTimeout(()=>{
        	//3초후 실행할 부분
       		img.remove();
            	resolve();
        }, 3000);
    });
}
//async & await 문법을 이용한 방법
async function showAvatar() {

  let img = document.createElement('img');
  img.src = githubUser.avatar_url;
  img.className = "promise-avatar-example";
  document.body.append(img);

  // 3초 대기
  await new Promise((resolve, reject) => setTimeout(resolve, 3000));

  img.remove();
}

showAvatar();

6. promise chaning의 경우 더욱 체감할 수 있다.

//promise chaining

//json 파일 가져오기
function loadJson(url) {
  return fetch(url)
    .then(response => response.json());
}

//user 정보 가져오기
function loadGithubUser(name) {
  return fetch(`https://api.github.com/users/${name}`)
    .then(response => response.json());
}

//아바타 가져오기
function showAvatar(githubUser) {

  return new Promise(function(resolve, reject) {
    let img = document.createElement('img');
    img.src = githubUser.avatar_url;
    img.className = "promise-avatar-example";
    document.body.append(img);

    setTimeout(() => {
      img.remove();
      resolve(githubUser);
    }, 3000);
  });
}

//json 파일 가져와서 url로 user정보를 가져온 후 avatar를 가져오는 함수 실행
loadJson('/article/promise-chaining/user.json')
  .then(user => loadGithubUser(user.name))
  .then(showAvatar)
  .then(githubUser => alert(`Finished showing ${githubUser.name}`));
  // ...
//await & async를 이용한 비동기 chaning 해결

async function showAvatar() {

  // JSON 읽기
  let response = await fetch('/article/promise-chaining/user.json');
  let user = await response.json();

  // github 사용자 정보 읽기
  let githubResponse = await fetch(`https://api.github.com/users/${user.name}`);
  let githubUser = await githubResponse.json();

  // 아바타 보여주기
  let img = document.createElement('img');
  img.src = githubUser.avatar_url;
  img.className = "promise-avatar-example";
  document.body.append(img);

  // 3초 대기
  await new Promise((resolve, reject) => setTimeout(resolve, 3000));

  img.remove();

  return githubUser;
}

showAvatar();

7. await는 'thenable 객체(then 메서드가 있는 호출 가능한 객체)'를 받을 수 있다.

: .then이 구현되어있으면서 프라미스가 아닌 객체를 받으면, 내장 함수 resolve와 reject를 인수로 제공하는 메서드인 .then을 호출한다.

//데모 thenable class 정의
class Thenable {
  constructor(num) {
    this.num = num;
  }
  
  //then 메서드
  then(resolve, reject) {
    alert(resolve);
    // 1000밀리초 후에 이행됨(result는 this.num*2)
    setTimeout(() => resolve(this.num * 2), 1000); // (*)
  }
};

async function f() {
  // 1초 후, 변수 result는 2가 됨
  let result = await new Thenable(1);	//then내부 resolve 혹은 reject가 호출되길 기다림
  alert(result);
}

f();

8. await promise는 promise 객체 result를 return, reject된 경우 throw문 처럼 error를 던진다. 그리고 try..catch로 잡을 수 있다.

//아래 두 코드는 동일하다.

async function f() {
  await Promise.reject(new Error("에러 발생!"));
}

async function f() {
  throw new Error("에러 발생!");
}
async function f() {

  //await promise에서 발생될 수 있는 error를 catch 하기 위함
  try {
    
    let response = await fetch('http://유효하지-않은-주소');
    let user = await response.json();
    
  } catch(err) {
    alert(err); // TypeError: failed to fetch
  }
}

f();

9. promise.allawait를 사용 가능 하다.

// 프라미스 처리 결과가 담긴 배열을 기다립니다.
let results = await Promise.all([
  fetch(url1),
  fetch(url2),
  ...
]);

 

 

참고

https://ko.javascript.info/async-await

 

async와 await

 

ko.javascript.info

 

Comments