ts-for-jsdev
  • 자바스크립트 개발자를 위한 타입스크립트
  • 들어가며
  • 01 타입스크립트 소개
    • 1.0 들어가며
    • 1.1 정적 타입 분석
    • 1.2 왜 타입스크립트인가
    • 1.3 타입스크립트의 구성요소
    • 1.4 타입스크립트의 역사
  • 02 ECMAScript
    • 2.0 ECMAScript
    • 2.1 블록 수준 스코프
      • 2.1.1 let을 이용한 선언
      • 2.2.2 const를 이용한 선언
      • 2.2.3 스코프 베스트 프랙티스
    • 2.2 객체와 배열
      • 2.2.1 비구조화 할당
      • 2.2.2 나머지 연산자와 전개 연산자
      • 2.2.3 객체 리터럴 변경사항
    • 2.3 함수
      • 2.3.1 기본 매개변수
      • 2.3.2 화살표 함수
    • 2.4 템플릿 리터럴
      • 2.4.1 멀티라인 문자열
      • 2.4.2 문자열 치환
    • 2.5 원소 순회
      • 2.5.1 forEach 메소드
      • 2.5.2 for-of 문법
      • 2.5.3 이터레이터 프로토콜
      • 2.5.4 이터러블 프로토콜
    • 2.6 비동기 처리
      • 2.6.1 프로미스
      • 2.6.2 Async / Await
    • 2.7 맺으며
  • 03 타입스크립트 기초 문법
    • 3.0 타입스크립트 기초 문법
    • 3.1 기본 타입
    • 3.2 배열과 튜플
    • 3.3 객체
    • 3.4 타입 별칭
    • 3.5 함수
    • 3.6 제너릭
    • 3.7 유니온 타입
    • 3.8 인터섹션 타입
    • 3.9 열거형
  • 04 인터페이스와 클래스
    • 4.0 들어가며
    • 4.1 인터페이스 기초
    • 4.2 색인 가능 타입
    • 4.3 인터페이스 확장
    • 4.4 클래스
    • 4.5 클래스 확장
    • 4.6 클래스 심화
      • 4.6.1 스태틱 멤버
      • 4.6.2 접근 제어자
      • 4.6.3 접근자
      • 4.6.4 추상 클래스
    • 4.7 인터페이스와 클래스의 관계
    • 4.8 맺으며
  • 05 타입의 호환성
    • 5.0 들어가며
    • 5.1 기본 타입의 호환성
    • 5.2 객체 타입의 호환성
    • 5.3 함수 타입의 호환성
    • 5.4 클래스의 호환성
    • 5.5 제너릭의 호환성
    • 5.6 열거형의 호환성
    • 5.7 맺으며
  • 06 타입 시스템 심화
    • 6.0 들어가며
    • 6.1 타입 좁히기
    • 6.2 타입 추론
    • 6.3 타입 단언
    • 6.4 집합으로서의 타입
    • 6.5 서로소 유니온 타입
    • 6.6 맺으며
  • 07 고급 타입
    • 들어가며 (7월 2일 공개)
  • 08 모듈과 네임스페이스
    • 들어가며 (7월 16일 공개)
  • 09 실제 프로젝트에서 사용하기
    • 들어가며 (7월 30일 공개)
  • 10 유용한 라이브러리 소개
    • 들어가며 (8월 13일 공개)
    • 맺으며
  • 부록 II : 자바스크립트 언어 생태계
    • ECMAScript 언어 표준과 TC39
    • TC39 프로세스
    • 실제 예시 - Array.prototype.includes
    • 타입스크립트와 ECMAScript
Powered by GitBook
On this page
  • then 과 catch 메소드
  • 프로미스 체인
  • 정리
  1. 02 ECMAScript
  2. 2.6 비동기 처리

2.6.1 프로미스

콜백 헬의 대안으로 가장 먼저 제안된 API는 프로미스(Promise)다. 프로미스는 비동기로 처리될 수 있는 연산에 사용되며, 생성자의 인자로 resolve와 reject, 두 핸들러를 인자로 받는 한 함수를 받다. 프로그래머는 함수 본문에서 (비동기로 작동할 수 있는) 특정 로직을 실행하고 그 결과에 따라 resolve 또는 reject를 호출할 수 있다.

function getRandomPromise () {
  return new Promise((resolve, reject) => {
    setTimeout(function () {
      const destiny = Math.random();
      if (destiny > 0.5) {
        resolve();
      } else {
        reject();
      }
    })
  });
}

then 과 catch 메소드

프로미스 인스턴스는 아래 두 개의 메소드를 갖는다.

  • resolve()의 호출된 경우, 즉 해당 비동기 작업이 완료 된 경우의 핸들러인 then()

  • reject()의 호출된 경우, 즉 해당 비동기 작업이 거부된 경우의 핸들러인 catch()

각 핸들러는 resolve() 혹은 reject()에 넘겨진 인자를 그대로 받는다. 프로미스가 완료되거나 거부되는 것을 처리되었다(setteled)고 하는데, 한 프로미스는 최대 한 번만 처리 될 수 있다. 즉 이미 완료 혹은 거부가 일어난 후의 또다른 resolve() 또는 reject() 호출은 무의미하다.

아래 예시에서는 웹에서의 네트워크 요청을 위한 Fetch API의 사용을 예로 살펴본다. 모던 브라우저에 내장되어 있는 fetch() 함수는 네트워크 요청을 만들기 위한 여러 정보를 인자로 받아 네트워크 요청을 실행하고, 그 요청에 연결된 프로미스를 리턴한다.

네트워크 요청이 성공적으로 끝난 경우, 이 프로미스는 내부적으로 서버가 넘긴 응답을 인자로 resolve()를 호출한다. 이 응답은 then() 핸들러에서 접근 가능하다.

fetch('http://example.com').then(response => {
  const  { ok, status } = response;
  console.log(ok, status); // true, 200
});

만약 네트워크 요청을 보내는 과정에서 오류가 발생했을 경우, 이 프로미스는 내부적으로 던져진 에러를 인자로 reject()를 호출한다. 이 응답은 catch() 핸들러에서 접근 가능하다.

fetch('https://this-is-invalid-url.really').catch(err => { 
  const { message } = err;
  console.log(message); // Failed to fetch
});

then 핸들러는 실제로는 두 개의 콜백을 인자로 받는다. 그 두 번째 콜백은 에러가 발생했을 때에 실행되며 에러 객체를 인자로 받는다. 즉 위 코드는 아래와 같이 다시 쓸 수 있다.

fetch('https://this-is-invalid-url.really').then(null, err => { 
  const { message } = err;
  console.log(message); // Failed to fetch
});

프로미스 체인

then과 catch 두 메소드는 호출된 경우 또다시 프로미스를 반환한다. 때문에 프로미스는 연쇄될 수 있다(chainable). 이 때, 프로미스 체인의 다음 프로미스는 이번 프로미스가 반환한 값으로 resolve를 호출한다.

fetch('http://example.com').then(response => {
  const { status } = response;
  return status;
}).then(status => {
  console.log(`The request has status ${status}!`); // The request has status 200!
});

종합하면, 프로미스가 지원되는 환경이라면 앞서 살펴보았던 콜백 헬 예제를 다음과 같이 고쳐 쓸 수 있다.

function errorHandler(err) {
  if (err) {
    console.log(err);
  }
}
fetchDocument(url)
.then(document => fetchAuthor(document), errorHandler)
.then(author => fetchPostsFromAuthor(author), errorHandler)
.then(posts => /* do something with posts */, errorHandler);

정리

콜백을 이용한 접근에 비해 갖는 장점을 금세 확인할 수 있을 것이다.

  • 들여쓰기의 깊이가 단계의 수에 비례해 늘어나지 않는다.

  • 코드의 흐름이 보다 한 눈에 들어온다.

  • 성공한 경우의 핸들러와 에러가 발생한 경우의 핸들러 중 한 쪽만 실행된다는 것이 보장되므로 if-else 문을 사용하지 않고 훨씬 깔끔한 코드를 작성할 수 있다.

Previous2.6 비동기 처리Next2.6.2 Async / Await

Last updated 7 years ago