[JavaScript] Promise

2021. 5. 12. 14:12Programming Languages/JavaScript

Promise는 기존의 비동기 처리에서 콜백 헬을 해결하기 위해 나온 ECMAScript 표준 사양입니다. Promise 이전에 비동기 처리를 하기 위해서는 비동기 처리가 완료되면 콜백 함수를 실행하는 방식을 사용하였습니다. 비동기로 가져온 데이터는 외부에서 사용할 수 없기 때문입니다. 이유는 비동기를 처리하는 브라우저의 방식 때문입니다. 이에 대해서는 다른 장에서 자세히 다루도록 합니다.

var asyncFn = requestData(apiURL, callback(data) => {
  requestData(apiURL, callback(data) => { 
    reqeustData(apiURL, callback(data) => { 	
      // ...
    } 
  }
})

이런 식으로 작성하게 되면 코드를 작성하기 힘들고 읽고 분석하는 데에도 많은 어려움이 있습니다. 가장 큰 문제는 에러 처리가 곤란하다는 점입니다.

try { 	
  setTimeout(() => { throw new Error('Error!!'); }, 1000); 
} catch (error) {
  // 에러가 잡히지 않음
  console.error('에러', error); 
}

catch에서 에러를 잡지 못한 것일까요? 기본적으로 error는 호출자에게 전파됩니다. 즉, 자신을 호출한 함수로 전달된다는 의미입니다. 하지만 setTimeout과 같은 비동기 함수는 평가됐을 때 Web API로 처리가 넘어가게 되고 콜 스택이 모두 비워진 다음 완료된 결과를 이벤트 루프를 통해 콜 스택에 전달되게 됩니다. 이는 setTimeout의 콜백 함수의 호출자는 setTimeout이 아니게 된다는 말입니다. 따라서 catch로 잡을 수 없게 됩니다. 프로미스는 이러한 문제를 해결했습니다.

사용법

프로미스는 new를 통해 생성합니다. 그리고 반환값은 프로미스 객체가 됩니다.

const promise = new Promise((resolve, reject) => { return resolve(data); });

프로미스의 상태는 세 가지의 상태로 관리합니다.

  • pending : 비동기 처리가 완료되지 않은 상태
  • fulfilled : 비동기 처리가 정상적으로 완료된 상태
  • rejected : 비동기 처리가 실패한 상태

먼저 프로미스를 실행하면 pending 상태가 됩니다. 그리고 비동기 처리가 진행되며 그 결과에 따라 프로미스의 상태가 변합니다.

  • 비동기 처리 성공 : resolve 함수를 호출하여 fulfilled 상태로 변경함
  • 비동기 처리 실패 : reject 함수를 호출하여 rejected 상태로 변경함
// resolve 함수가 호출되면 pending 상태였던 프로미스 객체는 fulfilled 상태로 변경됨
const fulfilled = new Promise(resolve => resolve(1));

// reject 함수가 호출되면 pending 상태였던 프로미스 객체는 rejected 상태로 변경됨
const rejected = new Promise((_, rejected) => reject(new Error("에러 발생")));

후속 메서드

프로미스를 통해서 처리한 데이터는 후속 메서드를 사용하여 이용할 수 있습니다.

  • then
  • catch
  • finally

then

then 메서드는 두 개의 콜백 함수를 인자로 받습니다.

  • 첫 번째 콜백 함수 - 전달된 프로미스의 상태가 fulfilled인 경우 호출됩니다. 이때 콜백 함수의 인자는 전달된 프로미스의 결과를 받습니다.
  • 두 번째 콜백 함수 - 전달된 프로미스의 상태가 rejected인 경우 호출됩니다. 이때 콜백 함수의 인자는 전달된 프로미스의 에러를 받습니다.
  • 반환값은 언제나 프로미스 객체입니다.
// fulfilled
new Promise((resolve) => resolve(1))
  .then((value) => console.log(value)); // 1
  
// rejected
new Promise((_, reject) => reject(new Error("에러 발생"))
  .then((value) => console.log(value), (err) => console.error(err));

catch

catch 메서드는 한 개의 콜백 함수를 인자로 받습니다. 콜백 함수는 프로미스의 상태가 rejected 인 경우에만 실행됩니다. then(undefined, reject)와 동일하게 동작합니다. 이 메서드 역시 언제나 프로미스 객체를 반환합니다.

new Promise((_, reject) => reject(new Error("에러 발생")) 
  .catch((err) => console.error(err)); 
  
// 위와 같음
// new Promise((_, reject) => reject(new Error("에러 발생"))
//	.then((value) => console.log(value), (err) => console.error(err));

finally

finally 메서드는 한 개의 콜백 함수를 인자로 받습니다. 콜백 함수는 fulfilledrejected 상태와 상관없이 무조건 한 번 호출됩니다. 비동기 처리의 성공이나 실패와 상관없이 실행해야 하는 코드를 작성해야 할 때 유용합니다. 이 메서드도 언제나 프로미스 객체를 반환합니다.

new Promise(() => {})
  .finally(() => console.log('finally')); // finally

'Programming Languages > JavaScript' 카테고리의 다른 글

[JavaScript] Promise Static Method  (0) 2021.05.12
[JavaScript] Promise Error Handling  (0) 2021.05.12
[JavaScript] 가비지 컬렉션  (0) 2020.08.17
[JavaScript] 객체 복사  (0) 2020.08.12
[JavaScript] 객체  (0) 2020.08.11