프론트엔드 개발자 - 자곰

카테고리 없음

Promise(1) - Promise란?

자곰 2023. 8. 1. 09:40

Promise는 자바스크립트에서 비동기적인 작업을 처리하기 위한 객체입니다. 비동기적인 작업은 주로 서버와의 데이터 통신, 파일 로딩 등이 해당됩니다. Promise 객체는 비동기 작업이 완료되었을 때 처리할 수 있는 값을 제공하며, 비동기 작업의 성공 또는 실패를 감지하고 관리하는데 사용됩니다.

먼저 Promise의 간단한 문법을 보겠습니다.

let promise = new Promise(function(resolve, reject) {
	// executor
});

new Promise에 전달되는 함수는 *executor(실행자, 실행 함수)*라고 부릅니다.

resolve와 reject는 자바스크립트에서 자체 제공하는 콜백입니다. 개발자는 resolve와 reject를 신경 쓰지 않고 executor 안 코드만 작성하면 됩니다.

executor에선 결과를 즉시 얻든 늦게 얻든 상관없이 상황에 따라 인수로 넘겨준 콜백 중 하나( resolve, reject )를 반드시 호출해야 합니다.

따라서 executor는 아래 그림과 같이 promise의 상태를 둘 중 하나로 변화시킵니다.

💡 Promise의 상태

1. pending: initial state, neither fulfilled nor rejected.

2. fulfilled: meaning that the operation completed successfully.

3. rejected: meaning that the operation failed. 

pending의 상태는 fulfilled가 될수도 있고 rejected가 될수도 있다.

❗️프라미스는 성공 또는 실패만 합니다.

executor는 resolve나 reject 중 하나를 반드시 호출해야 합니다. 이때 변경된 상태는 더 이상 변하지 않습니다. 한마디로, resolve나 reject가 호출되면 그 이후는 무시됩니다.

let promise = new Promise(function(resolve, reject) {
  resolve("완료");

  reject(new Error("…")); // 무시됨
  setTimeout(() => resolve("…")); // 무시됨
});

 

then, catch, finally

.then, .catch, .finally 메서드를 사용해 promise를 객체를 다룰 수 있습니다.

1. then.

.then첫 번째 인수는 프라미스가 이행되었을 때 실행되는 함수이고, 여기서 실행 결과를 받습니다.

.then두 번째 인수는 프라미스가 거부되었을 때 실행되는 함수이고, 여기서 에러를 받습니다.

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

// resolve 함수는 .then의 첫 번째 함수(인수)를 실행합니다.
promise.then(
  result => alert(result), // 1초 후 "완료!"를 출력
  error => alert(error) // 실행되지 않음
);

반대로 프라미스가 거부된 경우에는 아래와 같이 두 번째 함수가 실행됩니다. 두 번째 함수가 실행됩니다. 성공만 처리하고 싶으면 인수를 하나만 전달하면 됩니다.

2. catch

에러가 발생한 경우만 다루고 싶다면, .catch 를 쓰면 됩니다.

let promise = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error("에러 발생!")), 1000);
});

// .catch(f)는 promise.then(null, f)과 동일하게 작동합니다
promise.catch(alert); // 1초 뒤 "Error: 에러 발생!" 출력

.catch(f)는 문법이 간결하다는 점만 빼고 .then(null,f)과 완벽하게 같습니다.

💡 처리 되지 못한 Error는? 

에러를 처리하지 못하면 무슨 일이 생길까요? 체인 끝에 .catch를 추가하지 못하는 경우같은 경우입니다. 이런 경우엔 js엔진은 프라미스 거부를 추적하다가 실패하면 전역 에러를 발생시킵니다. 브라우저에선 이런 에러를 unhandledrejection 이벤트로 처리할 수 있습니다. 

unhandledrejection 이벤트는 HTML 명세서에 정의된 표준 이벤트입니다. 브라우저 환경에선 에러가 발생했는데 .catch가 없으면 unhandledrejection 핸들러가 트리거 됩니다.

3. finally

try {...} catch {...}에 finally 절이 있는 것처럼, 프라미스에도 finally가 있습니다.

finally 핸들러엔 인수가 없습니다. finally에선 프라미스가 이행되었는지, 거부되었는지 알 수 없습니다. finally에선 ‘보편적’ 동작을 수행하기 때문에 성공·실패 여부를 몰라도 됩니다.

또한, finally 핸들러는 자동으로 다음 핸들러에 결과와 에러를 전달합니다.

new Promise((resolve, reject) => {
  setTimeout(() => resolve("결과"), 2000)
})
  .finally(() => alert("프라미스가 준비되었습니다."))
  .then(result => alert(result)); // <-- .then에서 result를 다룰 수 있음

실습 예제

프로미스로 지연 만들기

function delay(ms) {
  return new Promise((resolve,reject) => {
	  setTimeout(resolve,ms)
  
  })
}

delay(3000).then(() => alert('3초후 실행'));