[JavaScript] ES6 - Promise

알린·2024년 5월 18일
0

Web

목록 보기
6/9

Promise

기존 비동기 처리 문제점

  • 비동기 처리를 하는 경우 Callback Hell에 자주 빠짐
    => Callback Hell
    • Callback 함수들이 중첩되어 순서를 정의하기 어려움
    • 에러 찾기 힘듦
    • 예외처리 정의하기 어려움

Promise 사용

  • 비동기 처리(ajax)을 편하게 처리할 수 있도록 ES6 에 도입된 문법

  • 비동기 작업의 완료 또는 실패를 나타내는 객체
    👉 비동기 처리가 성공할 때에는 resolve()를 호출, 실패할 때에는 reject()를 호출하도록 설계

  • ES6 Promise를 이용해 작업의 순서를 명확히 정의할 수 있음

    1. 처음 callback 함수에서 성공일 때는 resolve 함수와 연결, .catch실패케이스로 reject과 연결
    2. then을 통해서 비동기 작업이 성공했을때(resolve) 처리 해야할 일을 추가적으로 처리
    3. then을 연쇄적으로 여러번 설계(Chain)할수 있으며, then 내부의 return 값은 다음 메시지로 전달
  • 코드 구성

👩🏻‍💻 예시 코드

// promise 초기화 문법
const promise = new Promise((resolve, reject) => {
  // 비동기 처리 문장이 들어갈 곳
  // ex) ajax 요청, 파싱 ... 시간이 걸리는 작업
  let a = 1 + 1;
  if (a == 2) {
      // 성공했을 경우
      resolve('success!!');
  } else {
      // 실패했을 경우
      reject('failed!');
  }
});
// promise 실행하는 코드
promise.then((msg) => {
  // 비동기 처리가 완료되고, 비동기 처리된 결과를 가지고 업데이트 하는 영역
  // resolve가 호출되었을 때 오는 성공 패턴
  document.write('결과값: ' + msg);
}).catch((msg) => {
  // reject이나 error가 발생했을 경우 오는 영역
  document.write('결과값: ' + msg);
});

Chain 패턴

  • 비동기 처리를 하기 위해선 then을 여러개를 chain으로 붙여 활용

  • Promise의 then은 chain으로 설계
    👉 chain은 자기 자신(this)를 return하는 패턴

  • then은 then((msg)=>msg + '...')로 설계, msg는 이전 msg, return값은 다음 then으로 전달

  • then chain 실행 도중 에러를 발생시키면 chain이 중지
    👉 then()내부에서 오류가 발생하면 가장 가까운 catch()가 호출됨

  • throw new Error('')를 통해 사용자 에러를 발생시켜 중지시켜도 됨

👩🏻‍💻 예시 코드

count = 0;
element = document.getElementById('p1');
function run() {
  const promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
          resolve('3000ms 이후 발생하는 메시지!');
      }, 3000); // 3000ms 이후 실행되는 문장
  });
  // 연속적인 비동기 작업을 처리하기 위해선 then chain으로 설계한다.
  promise2.then((msg) => {
      console.log(msg);
      element.innerHTML += 'then1, 이전 msg : ' + msg + '<br>';
      return count++; // 리턴되는 값은 다음 then, msg 전달된다. 
  }).then((msg) => {
      element.innerHTML += 'then2, 이전 msg : ' + msg + '<br>';
      // throw new Error('에러 메시지!'); // 에러 발생시 catch로 전달됨
      return count++;
  }).then((msg) => {
      element.innerHTML += 'then3, 이전 msg : ' + msg + '<br>';
      return count++; // 2가 되지만 출력은 되지 않음!
  }).catch((error) => {
      element.innerHTML += 'error : ' + error + '<br>'; // 에러 발생시 해당문구 출력
  });
}

fetch

  • 서버로부터 데이터를 가져오기 위한 ajax 처리를 위해 설계된 라이브러리
  • XMLHttpRequest 대체 기능으로 설계됨
  • 필드에서는 fetch 라이브러리의 호환성 이슈로 인하여 jQuery-ajaxaxios를 주로 활용
  • CORS(도메인 외부 리소스가져오기)HTTP Origin 헤더를 설정하는 등의 기능을 지원
  • GET / POST / PUT / PATCH / DELETE 처리
  • 대표적인 promise 기반으로 설계 되었으며, promise 패턴처리 가능

👩🏻‍💻 예시 코드
주간/주말 박스오피스 API 서비스 링크

// fetch(url, options)
// .then((response) => console.log("response:", response))
// .catch((error) => console.log("error:", error));
function runFetch() {
    let url = document.getElementById('url').value;
    url += '?key=' + '4298055d882fbc5';
    url += '&targetDt=' + document.getElementById('targetDt').value;
    console.log(url);
    fetch(url)
        .then((response) => {
            console.log(response);
            if (response.status != 200) { // 200이 아니면 error인 상황!
                throw new Error('Request Error!');
            }
            return response.json();
        }).then((json) => {
            console.log(json);
            const rankArray = json.boxOfficeResult.weeklyBoxOfficeList;
            if (rankArray == null || rankArray.length == 0) {
                throw new Error('json parse Error!');
            }
            let e = document.getElementById('print');
            e.innerHTML = '';
            rankArray.forEach((data) => {
                let html = `<div>
                                    ${data.rank} - ${data.movieNm},
                                    일일 관객 : ${data.audiCnt}, 누적 관객 : ${data.audiAcc}
                                </div>`;
                e.innerHTML += html;
            });
        }).catch((error) => {
            alert(error);
        });
}

async/await

  • promise를 쉽게 활용하도록 설계된 문법

  • 비동기 함수의 앞부분에 async를 선언하고,
    promise 실행시에는 await 키워드를 붙여줌

  • await가 붙은 함수는 함수가 모두 실행 될때까지 block되며,
    모두 실행되면 다음 문장이 실행

👩🏻‍💻예시 코드

function delay(ms) {
  return new Promise(resolve => {
      setTimeout(() => {
          alert(ms + 'ms초가 지났습니다.');
          resolve();
      }, ms);
  });
}
// 기존 promise then() 구조로 여러개를 실행시켜 보기
function test1() {
  delay(1000).then(() => {
      // 성공했을 경우 resolve로 호출되는 영역
      return delay(1000);
  }).then(() => {
      return Promise.resolve('끝');
  }).then((msg) => {
      alert(msg);
  });
}
// 동일한 기능을 가지는 async/await 설계
// async를 사용하기 위해선 함수 앞에 반드시 async가 필요!
async function test2() {
  await delay(1000);
  await delay(1000);
  const result = await Promise.resolve('끝');
  alert(result);
}
// 동기화 안한 함수 -> 결과가 이상하게 동작한다! 실패!
function test3() {
  delay(1000);
  delay(1000);
  const result = Promise.resolve('끝');
  alert(result);
}

async/await 기반 fetch

  • fetch는 promise 기반으로 설계되어 있음으로 async/await로 전환하여도 활용 가능

👩🏻‍💻 예시 코드

async function updateView(json) {
    let e = document.getElementById('print2');
    const rankArray = json.boxOfficeResult.weeklyBoxOfficeList;
    e.innerHTML = '';
    rankArray.forEach((data) => {
        let html = `<div>
                            ${data.rank} - ${data.movieNm},
                            일일 관객 : ${data.audiCnt}, 누적 관객 : ${data.audiAcc}
                        </div>`;
        e.innerHTML += html;
    })
}
async function runAsyncAwait() {
    let url = document.getElementById('url2').value;
    url += '?key=' + '4298055d882fbc5c120b654c1fa42815'
    url += '&targetDt=' + document.getElementById('targetDt2').value;
try {
    const response = await fetch(url);
    console.log(response);
    if (response.status != 200) {
        alert('request error!');
        return;
    }
    const json = await response.json();
    console.log(json);
    const rankArray = json.boxOfficeResult.weeklyBoxOfficeList;
    if (rankArray == null || rankArray.length == 0) {
        alert('json parse error!');
        return;
    }
    await updateView(json);
} catch (e) {
    alert(e);
}

}











































































  
  
  
  
  
  
profile
Android 짱이 되고싶은 개발 기록 (+ ios도 조금씩,,👩🏻‍💻)

0개의 댓글