Promise에 대해서

🌊·2023년 6월 18일
0

JS&TS

목록 보기
6/6
post-thumbnail

개요

오늘은 Promise에 대해서 이야기를 나눠보려고 합니다.

요즘 들어서 기본 개념이 매우매우 부족하다는 생각을 하고 있습니다.. 🤦‍♂️
사실 Promise에 대해서 공부하려고 하는 것도.. axios 라이브러리에 대해서 찾아보다가.. 이해가 잘 되지 않아서.. 찾아보게 되었습니다..

이러면서.. react-query와 같은 라이브러리를 사용하겠다는 제 자신이 조금 부끄러워집니다.. 💩
그래도 이렇게 하나씩 배워가는거 아니겠나..! 라는 생각으로 정리해보려고 합니다.

Promise

  • 자바스크립트 안에 내장되어 있는 객체(Object)
  • 비동기 동작을 위한 객체(Object)
  • stateProducer vs Consumer 2가지의 포인트를 가지고 개념을 이해하는 것이 좋다

Promise 생성

const promise = new Promise((resolve, reject) => {
	... // executor
})

Promise는 위와 같은 문법으로 생성할 수 있습니다.

new Promise() 에 전달되는 함수는 executor라는 이름을 가지고 있는데, (resolve, reject) => {}와 같은 형태를 가지고 있습니다.
executor함수는 new Promise가 생성될 때 자동으로 실행됩니다.

executor의 인수

executorresolve, reject 2가지 인수를 받을 수 있습니다.
resolvereject는 자바스크립트에서 자체적으로 제공하는 콜백 함수입니다.
따로 선언할 필요 없이 executor 함수 안에 작성만 해주면 됩니다.

대신 executor에서는 결과를 얻는 시점과 상관없이 상황에 따라 resolvereject 콜백 함수 중 하나를 반드시 호출해야 합니다.
왜냐하면, executor는 생성과 동시에 실행하게 되는데 executor 내부에서 로직을 처리하게 됩니다.
처리가 끝나면 바로 resolve 혹은 reject 콜백 함수를 호출하게 됩니다.

resolve, reject

  • executor의 처리 성공 여부에 따라 실행되는 콜백함수
  • resolve(value): 작업을 성공한 경우 결과(value)와 함께 호출
  • reject(error): 에러 발생 시 에러 객체를 나타내는 error와 함께 호출

Producer

  • 정보를 제공하는 주체
  • 파일을 읽어나 네트워크 작업을 하는 등의 시간이 오래 걸리는 작업을 수행하고, 수행한 결과에 대한 데이터나 에러를 반환한다
const promise = new Promise((resolve, reject) => {
	... // executor
	setTimeout(() => {
		// 성공
		resolve('success!')

		// 실패
		reject(new Error('error!'))
	}, 1000)
})

executor의 로직(파일을 읽거나 네트워크 작업과 같은 작업)을 수행한 후 성공했을 때는 resolve()를 통해서 받아온 값을 전달할 수 있습니다.
반대로 실패한 경우에는 reject()Error 객체를 통해서 실패에 대한 값을 전달하게 됩니다.
Error 객체는 자바스크립트에서 제공하는 객체 중 하나입니다.

Consumer

  • 정보를 사용하는 주체
  • new Promise 생성자가 반환하는 promise 객체
  • then, catch, finally를 이용해서 값을 받아올 수 있다

Promise의 상태와 값 (Consumer의 상태)

new Promise 생성자가 반환하는 Promise는 상태(status)와 값(result)을 가지게 됩니다.
상태는 pending, fulfilled, rejected가 있고, 상태에 따라 값(result)이 바뀌게 됩니다.
이러한 상태의 변경은 producer에서 어떠한 함수를 호출하는가에 따라 달라지게 됩니다.

pending

  • promise₩ 객체의 초기 상태 혹은 실행 중인 상태
  • resultundefined

fulfilled

  • producer에서 resolve가 호출되면 나타나는 상태 (성공)
  • resultresolve(value)value로 값이 바뀌게 된다.

rejected

  • producer에서 reject가 호출되면 나타나는 상태 (실패)
  • resultreject(error)error로 값이 바뀌게 된다.

then, catch, finally

const promise = new Promise((resolve, reject) => {
	resolve('success!')
	reject(new Error('error!'))
})

then

  • resolve 콜백 함수를 통해서 전달된 값을 사용할 수 있다
  • 또한 promise도 전달할 수 있다.
proimise
	.then((value) => console.log(value)) // success!

value라는 파라미터는 resolve에서 전달하는 값을 받는 파라미터입니다.
그래서 value라는 명칭을 고정해서 사용해야 하는 것은 아니고 적절한 명칭을 사용하면 됩니다.

catch

  • reject 콜백 함수를 통해서 전달된 에러에 대한 값을 사용할 수 있다
promise
	.catch((error) => console.log(error)) // Error: error! at ...

reject 콜백함수에서 전달한 error에 대한 값을 catch로 받지 않게 되면 Uncaught 에러로 표현되게 됩니다.
그래서 에러 핸들링을 위해서 catch를 이용해서 실패에 대한 케이스를 처리해줘야 합니다.

finally

  • executor의 성공과 실패 여부와 상관없이 무조건 호출되는 함수
promise
	.finally(() => console.log('finally!'))

만약 promise에 대한 then, catch 작업을 진행하고 싶다면 아래와 같이 Promise Chaining 형식으로 작성해야 합니다.
.then에 대한 반환 값도 promise이기 때문에, .catch에 대한 처리를 진행할 수 있습니다.

promise
	.then((value) => console.log(value))
	.catch((error) => console.log(error))
const promise = new Promise((resolve, reject) => {
	console.log("doing something...");
	
	setTimeout(() => {
		reject(new Error("no network"));
	}, 1000);
});

promise
	.then((value) => console.log(value))
	.catch((error) => console.log(error))
	.finally(() => console.log("finally"));

위와 같은 코드에서는 Error: no network at ...와 같은 메시지와 finally 문자열이 콘솔에 찍히게 될 것입니다.
만약 catch에 대한 처리를 해주지 않아도 Uncaught 에러와 함께 finally는 작동하게 됩니다.

Promise Chaining and Error Handling

const getHen = () =>

new Promise((resolve, reject) => {
	setTimeout(() => resolve("hen"), 1000);
});

const getEgg = (hen) =>
	new Promise((resolve, reject) => {
	// setTimeout(() => resolve(`${hen} => egg`), 1000);
	setTimeout(() => reject(new Error(`error! ${hen} => egg`)));
});

const cook = (egg) =>
	new Promise((resolve, reject) => {
	setTimeout(() => resolve(`${egg} => fried`), 1000);
});

  

getHen()
	// .then((hen) => getEgg(hen))
	// callback 함수를 전달할 때 받아오는 value를 다른 함수에서 바로 호출하는 경우에는 생략이 가능하다.
	.then(getEgg)
	// egg를 받아올 때 문제가 생긴다면 catch를 통해서 다른 것을 전달해줄 수 있다.
	.catch(() => {
		return "bread";
	})
.then((egg) => cook(egg))
.then((meal) => console.log(meal))
.catch(console.log);

마무리

오늘은 Promise에 대해서 알아보았습니다.
자바스크립트 책을 한 권 스터디하는 것도 좋을 것 같다는 생각이 듭니다.. 🤔

ProducerConsumer의 개념을 사용한 것은 제가 참고한 유튜브에서 사용한 방식이기 때문에 공식적인 단어는 아닌 것으로 알고 있습니다.
해당 내용 참고하셔서 봐주시면 감사하겠습니다. 🙏

출처

0개의 댓글