Promise 란?
Promise 객체는 비동기 작업을 다루기 위해 만들어졌으며, 비동기 작업의 성공 혹은 실패 후 결과를 처리하기 쉽게 해준다. 또한 비동기 작업이 끝나고 실행할 콜백을 등록할 수 있는 메서드를 제공한다.
Promise 객체가 탄생하기 전에는 비동기 처리를 위해 콜백함수를 사용했는데, 일명 콜백 헬로 불리는 문제로 인해 가독성이 나쁘고 에러 처리가 분산되고 흐름의 추적하기 어려워지는 등 불편함이 있었는데 이러한 불편함을 보완할 수 있는 것이 Promise 이다.
Promise 상태
Pending : 아직 대기 중인 상태
Fulfilled : 비동기 작업이 성공적으로 완료된 상태이며, resolve 로 인해 pending 상태에서 fulfilled 상태로 변함
Rejected : 비동기 작업이 실패한 상태이며, reject 로 인해 pending 에서 rejected 상태로 변함
연습
API 호출은 비동기 작업이어서 promise 를 사용한다. fetch 함수를 사용하면 promise 객체를 반환하므로 비동기 작업 처리를 쉽게 할 수 있다. 테스트를 위해 jsonplaceholder 를 사용해 보자.
- 예시 코드 1
import React, { useState, useEffect } from "react";
function App() {
const [post, setPost] = useState(null);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((response) => response.json())
.then((json) => setPost(json))
.catch((error) => console.error("오류 발생 => ", error));
}, []);
return <div>{post ? <div>{post.title}</div> : <div>Loading...</div>}</div>;
}
export default App;
위 코드의 동작 방식은 다음과 같다.
컴포넌트가 마운트될 때 useEffect 가 실행되어 fetch 함수를 사용해 비동기적으로 외부 API 로부터 데이터를 가져온다. fetch 함수는 Promise 객체를 반환하며, 호출 성공 시 then 블록에서 데이터를 받아 실행되어 setPost 를 사용해 상태를 업데이트하며, 실패 시 catch 블록에서 오류를 처리한다. 이렇게 promise 객체로 then 과 catch 를 사용하여 비동기 작업의 성공 실패 처리를 쉽게 할 수 있는 것을 알 수 있다.
- 예시 코드 2
import React, { useState, useEffect } from "react";
function App() {
const [post, setPost] = useState(null);
useEffect(() => {
const fetchPost = async () => {
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts/1"
);
const data = await response.json();
setPost(data);
} catch (error) {
console.log("error :>> ", error);
}
};
fetchPost();
}, []);
return <div>{post ? <div>{post.title}</div> : <div>Loading...</div>}</div>;
}
export default App;
async/await 를 사용하여 promise 객체를 더 쉽게 다룰 수 있다.
async 함수는 promise 객체를 반환하며 await 키워드는 promise 가 수행될 때까지 기다린다. 그 후에 다음 코드를 실행한다.
고찰(?)
그러면 첫 번째 예시와 두 번째 예시의 차이점은 무엇일까? 두 예시 모두 fetch 를 사용하여 데이터를 가져오는 것은 똑같다. 차이점은 첫 번째는 Promise 체이닝 방식이고, 두 번째 코드는 async/await 방식을 사용한다. 물론 상황에 따라 맞는 것을 선택해서 사용하면 되겠지만 일반적으로는 async/await 를 권장한다고 한다.
그 이유는 다음과 같다.
- 가독성 및 유지보수
promise 체이닝 방식은 충접되거나 길어지면 읽기 어렵고 복잡해지는데, async/await 는 비동기를 마치 동기처럼 코드를 작성하기 때문에 디버깅이나 유지보수가 더 수월하다.
const response = await fetch(...);
const data = await response.json();
이 부분이 마치 동기처럼 순차적으로 동작하는 것을 명확하게 표현해 주고 있다.
- 에러 처리
async/await 방식은 try-catch 문을 사용하여 에러를 처리할 수 있다. 이는 에러가 발생한 곳을 명확하게 파악할 수 있다. 하지만 promise 체이닝 방식은 catch 블록을 통해 에러를 처리하지만, 비동기 함수 내부에서 발생한 에어를 모두 잡기에는 불편할 수 있다고 한다.
정리하자면, async/await 방식이 더 현대적일뿐더러, 가동성, 유지보수, 에러처리 방면에서 장점이 많아서 더 선호한다고 한다.
'Javascript' 카테고리의 다른 글
[Javascript] let/const/ var (0) | 2024.07.29 |
---|---|
스크롤 이벤트 발생 시 스크롤 진척도 표시 (0) | 2024.07.19 |
스크롤 특정 영역 감지 (0) | 2024.07.17 |
버튼 클릭시 스크롤 맨 위로 이동 (1) | 2024.07.16 |
[Javascript] Array.prototype.join() (0) | 2024.06.05 |