Javascript 프로미스(Promise)2020-10-26

#JS#Basic

Promise

Promise를 알아보기 전에 우선 Promise가 나오게된 이유에 대해서 알아볼 필요가 있다.

자바스크립트에서는 비동기 요청이 자주 사용되곤 한다.
비동기식 요청은 처리방식을 병렬로 진행하여 기존 처리와 동시에 진행되는 장점이 있다.
하지만 비동기가 처리된 후 받아온 데이터를 이용한 처리가 되어야 할 경우 콜백을 이용해 처리하게 되는데 이 형태가 중첩될 경우 콜백헬이 형성되게된다.

var count = 1

function api (param, callback) {
  $.get(`/api/${count}`, function(res) {
    count++
    $.get(`/api/${count}`, function(res) {
      count++
      $.get(`/api/${count}`, function(res) {
        count++
        ...
      })
    })
  })
}

위의 예시가 극단적이긴 하지만 콜백지옥의 예이다.
이런 콜백지옥 현상을 조금 개선하고자 나온 것이 Promise라고 할 수 있다.

Promise는 프로미스가 생성될 때 꼭 알 수 있지는 않은 값을 위한 대리자로,
비동기 연산이 종료된 이후의 결과값이나 실패 이유를 처리하기 위한 처리기를 연결할 수 있도록 합니다.

MDN에서 발췌해온 Promise에 대한 설명이다.
설명에서처럼 Promise는 비동기처리가 끝난 후 나온 값을 연속해서 처리하기를 도와준다고 할 수 있다.

var count = 1

function promiseFunction () {
  return new Promise(function (resolve, reject) {
    resolve($.get(`/api/${count}`))
  })
}

위가 프로미스의 기본적인 형태이다.
Promise는 기본적으로 인스턴스를 생성해서 사용하게된다.
인스턴스 생성시 resolve, reject를 인자로 받는 함수를 파라미터로 받는데 resolve는 비동기처리가 성공했을 경우 호출하여 값 넘겨주는 역할을 하고 reject은 비동기처리가 실패했을 때 넘겨줄 값을 넣어주게된다.

이제 호출하는 부분을 보면 아래와 같이 수정될 수 있다.

var count = 1

function promiseFunction () {
  return new Promise(function (resolve, reject) {
    $.get(`/api/${count}`, function(res) {
      resolve(res)
    })
  })
}

function api (param, callback) {
  promiseFunction().then(function() {
    count++
    return promiseFunction()
  }).then(function() {
    count++
    return promiseFunction()
  }).then(function() {
    count++
    return promiseFunction()
  })
  ...
}

확실히 위에서 본 뎁스가 계속 깊어지면서 가독성이 낮아지는 형태보다는 보기가 편해졌다.
앞에서 실행한 비동기 함수에서 Promise를 다시 리턴해주고 then을 통해서 다시 resolve된 값을 받아 연속적으로 다음 함수를 처리할 수 있도록 되는 모습을 볼 수 있다.


Promise의 예외처리

Promise의 형태와 사용법을 알아봤는데 그렇다면 예외처리는 어떻게 할까?
보통의 자바스크립트에서 발생하는 예외를 처리하는 방법은 try catch를 이용 할 수 있는데 예시를 보면 아래와 같다.

function errorTest() {
  throw new Error('에러')
}

try {
  errorTest()
} catch (e) {
  console.log(e) // Error: 에러 ...
}

그렇다면 Promise의 예외처리도 try catch를 쓰면될까?

function promiseError() {
  return new Promise(function(resolve, reject) {
    reject(new Error('에러'))
  })
}

try {
  promiseError()
} catch (e) {
  console.log(e)
}

// Uncaught (in promise) Error: 에러

try catch를 사용해 예외처리를 했지만 콘솔로 찍히는 것은 예외처리가 되지 않았다는 에러이다.
사실 비동기 처리의 예외처리는 try catch 문으로는 잡을 수 없다.
그 이유는 비동기이기 때문인데, 풀어서 말하자면 try catch와 비동기 처리가 병렬로 진행되기 때문에 비동기 처리가 끝났을 때는 이미 try catch도 끝난 상태이기 때문이다.

그래서 Promise에서 예외처리는 .catch 메소드를 이용해서 하게된다.

function promiseError() {
  return new Promise(function(resolve, reject) {
    reject(new Error('에러'))
  })
}

promiseError().catch(function(e) {
  console.log(e) // Error: 에러 ...
})

위의 예시와 같이 Promise를 호출하고 .catch를 이용해서 에러처리를 하게되면 Uncaught가 발생하지 않고 제대로 예외처리가 되게된다.