상세 컨텐츠

본문 제목

javascript.info - 프라미스와 async, await(3)

개발공부/개발공부

by Dal_pang 2023. 1. 2. 15:46

본문

     11.8 Async와 Await    

    async 함수    

function앞에 async 키워드를 붙여 사용.

async function f() {
  return 1;
}

*** function앞에 async를 붙이면 해당 함수는 항상 프라미스를 반환한다.

프라미스 아닌값을 반환해도, 자동으로 resolved promise 형태를 만들어 감싸준다(wrap).

 

   await   

async함수 안에서만 동작하는 키워드.

// await는 async 함수 안에서만 동작합니다.
let value = await promise;

자바스크립트는 await키워드를 만나면 프라미스가 처리될 때까지 기다리고, 그 이후에 결과를 반환.

example)

async function f() {

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("완료!"), 1000)
  });

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

  alert(result); // "완료!"
}

f();

함수 호출 후 (*)라인에서 실행이 중단되었다가 프라미스가 처리된 후 실행이 재개됨. 

말 그대로 프라미스가 처리될 때까지 함수 실행을 기다리게 하는 역할.

 

promise.then 보다 더 세련되게 프라미스의 result값을 얻을 수 있게 해주는 문법. promise.then보다 가독성 좋고 쓰기 쉬움.

 

async/await 예제

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();

 - async/await 적용 전 - 

더보기

promise.then으로 작성된 코드.

function loadJson(url) {
  return fetch(url)
    .then(response => response.json());
}

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);
  });
}

// 함수를 이용하여 다시 동일 작업 수행
loadJson('/article/promise-chaining/user.json')
  .then(user => loadGithubUser(user.name))
  .then(showAvatar)
  .then(githubUser => alert(`Finished showing ${githubUser.name}`));
  // ...

 

await은 최상위 레벨 코드에서 사용 불가.

 

   에러 핸들링   

프라미스 정상 이행시 await promise는 객체의 result에 저장된 값 반환. 거부시 throw문 작성한 것 처럼 에러 던져짐.

async function f() {
  await Promise.reject(new Error("에러 발생!"));
}
// -- 위 아래 동일하게 작동 ---
async function f() {
  throw new Error("에러 발생!");
}

await이 던진 에러는 throw가 던진 에러 처리할때 처럼 try..catch 사용해 잡을 수 있음.

async function f() {

  try {
    let response = await fetch('http://유효하지-않은-주소');
    let user = await response.json();
  } catch(err) {
    // fetch와 response.json에서 발행한 에러 모두를 여기서 잡습니다.
    alert(err);
  }
}

f();

*** try..catch가 없으면 프라미스가 거부 상태가 됨.

 

.catch를 추가하는 걸 잊으면 처리되지 않은 프라미스 에러가 발생. 

이런 에러는 unhandledrejection을 사용해 잡을 수 있다.

 

 

*** async/await이 promise.then/catch보다 선호된다.

단, 가끔 가장 바깥 스코프에서 비동기 처리가 필요할 경우와 같은 경우에는 promise.then/catch 를 써야할 경우가 있음.

async/await은 프라미스 기반이라는 것 잊지 말것. 

(Promise.all을 통해 작업들이 모두 완료될 때까지 기다릴수 있다는 것도 잊지 말기!)

 

*** async/await은 Promise.all과 함께 사용 가능.

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

 

요약

function 앞에 async 키워드 추가시

1) 함수가 언제나 프라미스 반환

2) 함수 안에서 await사용 가능.

 

프라미스 앞에 await 키워드를 붙이면 프라미스가 처리될 때까지 대기. 처리 완료 되면 다음과 같이 동작.

1) 에러 발생 - 예외 생성됨(throw error과 동일한 동작)

2) 에러 미발생  - 프라미스 객체의 result값을 반환

 

 

728x90

관련글 더보기