Promises 사용법과 Async Await 주의점

이원찬·2024년 7월 14일

javascript

목록 보기
3/5

Promise 란? 🤔

비동기 연산의 상태를 나타내는 객체이다!

비동기 프로그래밍을 보다 간결하게 표기 하기 위해 ES6에서 등장한 문법이다!

비동기란?

https://velog.io/@twoone14/동기비동기-블로킹논블로킹

위 포스팅에서 자세히 알아 볼수 있습니다.

Promise 사용방법

(new Promise((resolve, reject) => {
	if(isSuccess) 
		resolve("여기가 맛집인가?"); // 비동기 작업의 결과를 resolve함수를 호출하며 넘긴다.
	else 
		reject(new Error("맛집 아닌듯.."));
}))
// then 체이닝으로 비동기 작업이 끝났을때 할 작업을 넘겨 줄수 있다.
// resolve로 넘긴 데이터가 then의 콜백인자로 넘어온다.
.then((result) => {
	console.log(result); // "여기가 맛집인가?"
})
// catch 체이닝으로 비동기 작업이 거절, reject, 에러 가 났을때 작업을 넘겨 줄수 있다.
// reject로 넘겨준 에러가 catch 의 콜백 인자로 넘어오게 된다.
.catch((e) => {
	console.error(e); // Error "맛집 아닌듯.."
});
  • then으로 비동기 작업이 끝났을때의 결과를 받아 다음 작업을 지시 할수있다.
  • catch로 비동기 작업중 생긴 오류를 넘겨받아 오류시 실행할 작업을 지시 할수있다.

setTimeout과 Promise 같이 사용해보기! 👉

new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve("3초 끝~");
	}, 3000) //3초 대기
}).then((message)=> {
	console.log(message); // 3초뒤 "3초 끝~" 가 콘솔에 출력됨!
})

실제로 살펴본 Promise 객체

비동기 작업의 상태에 따라 Promise 객체는 아래와 같은 상태를 가진다.

  • 비동기 작업이 시작했을때 Pending이라는 상태를 가진다.
  • 비동기 작업이 성공했을때 “fulfilled” 라는 상태를 가진다.
  • 비동기 작업이 실패 했을때 “rejected” 라는 상태를 가진다.

Promise 를 사용하기 전 비동기 프로그래밍 방법

Promise 객체가 나오기 전에는 콜백 ( 나중에 호출될 함수 ) 를 인자로 넘겨주어 가독성이 심하게 좋지 않았음

예시 )

비동기 함수 정의

const aFun = (successCallback, errorCallback) => {
	const isSuccess = true | false  // 어떤 비동기 작업
	if (isSuccess) {
		successCallback();
	} else {
		errorCallback();
	};
}

비동기 함수를 호출하는 곳

aFun(() => {
	console.log("여기 성공했음!");
} , () => {
	console.log("여긴 실패!");
})

예시는 callback을 하나만 중첩 시켰지만 비동기 함수를 2번, 3번 씩 중첩하여 호출하게 된다면 아래와 같은 모습이 만들어 질것이다.

aFun1(() => {
	aFun2(() => {
		aFun3(()=> {
			console.log("여긴 어디...");
		})
	})
});

이렇게 콜백이 많이 호출 되며 들여쓰기가 많아 가독성이 떨어지는 상태를 콜백 지옥 (Callback Hell) 이라고 부른다.

async-await 란? 🤔

Promise 의 완료를 기다리기 위한 문법이다.

아래와 같이 Promise 를 await 로 기다려 보자

Promise 객체가 찍히는게 아니라 resolve 된 결과 값인 ‘abc’ 가 콘솔에 찍히게 된다.

주의점 ❗

콘솔 전역 환경에서는 await 문법이 전역에서 사용가능하지만 함수 안에서는 async 키워드와 함께 같이 사용해야만 한다.

await is only valid in async functions and the top level bodies of modules

// await은 비동기 함수와 모듈의 최상위 바디에서만 유효합니다.

async await 에서 에러 핸들링은 try-catch 문에서 사용해야한다.

// 에러 핸들링이 안되는 코드
let a = async () => {
	let result = await fetch('무효한 url'); // 에러가 나도 잡을 reject가 없기에 잡을수 없음
}

// try-catch 로 에러 핸들링을 하는 코드
let a = async () => {
	try {
		let result = await fetch('무효한 url');
	} catch (e) {
		console.error(e); // 에러 발생시 catch 블락의 코드가 실행됨!
	}
}

여러개의 비동기 함수를 호출할때에는 await를 신중히 사용하자

아래와 같은 비동기 작업을 하는 delay 함수를 만들었다 가정하자.

const delay = (millisec) => {
	return new Promise((resolve, reject) => {
		setTimeout(()=>{
			resolve();
		}, millisec)
	})
};

await 를 이용해 위 delay함수를 3번 호출한다면 어떻게 될까

const a = async () => {
	await delay(1000) // 1초대기
	await delay(2000) // 2초대기
	await delay(3000) // 3초대기
	console.log("6초나 기다려야함;;"); // 6초를 기다려야 아래 코드가 실행된다.
};

delay라 이름을 지어놔서 6초를 기다리는게 당연한 것처럼 보이지만 delay가 아니라 api 호출 함수였다면…?

병렬적으로 api 호출을 해야하기에 문제가 생긴다.

아래와 같이 Promise.all 또는 Promise.allSettled 를 이용하여 병렬적으로 모든 Promise를 기다리자

await Promise.all([delay(1000), delay(2000), delay(3000)]
// 가장 오래기다리는 3초를 기다린뒤 아래 코드가 실행된다.

참고자료

https://www.youtube.com/watch?v=li7FzDHYZpc&pp=ygURcHJvbWlzZSBhc3ljIGFhaXQ=

https://www.youtube.com/watch?v=iUGLyhbwYkU&pp=ygUZcHJvbWlzZSBhc3ljIGF3YWl0IOyEpOuqhQ==

https://ko.javascript.info/async-await

https://www.youtube.com/watch?v=cDu9A5dl1J8

profile
소통과 기록이 무기(Weapon)인 개발자

0개의 댓글