3. Promise로 비동기 처리하기
Promise는 비동기 처리를 위한 객체로, 프로미스를 이용하면 콜백 함수를 사용하지 않고도 더 쉽게 비동기 처리를 할 수 있다.
프로미스는 세 가지 상태를 가진다.
- 대기(pending) : 비동기 처리가 아직 수행되지 않은 상태
- 이행(fulfilled) : 비동기 처리가 성공적으로 수행된 상태
- 거부(rejected) : 비동기 처리가 실패한 상태
프로미스를 사용하여 비동기 처리를 하려면, new Promise()를 사용하여 프로미스 객체를 생성하고, resolve와 reject를 사용하여 프로미스의 상태를 변경한다.
- 프로미스 객체 생성
- Vanilla JavaScript
// 프로미스 객체 생성
// new Promise((resolve, reject) => {...})를 통해 새로운 프로미스 객체 생성
// 이 객체는 비동기 작업을 수행할 콜백 함수를 인자로 받으며,
// 이 콜백 함수는 resolve와 reject라는 두 개의 함수를 매개변수로 가집니다.
// resolve, reject 함수는 프로미스의 상태를 변경하는 역할을 합니다.
const coffeeOrder = new Promise((resolve, reject) => {
// 커피 제조 과정을 시뮬레이션하기 위해 setTimeout 함수를 사용합니다.
// 이는 바리스타가 커피를 제조하는 데 시간이 걸리는 것을 나타냅니다.
setTimeout(() => {
// 바리스타가 커피를 성공적으로 제조했다고 가정하고, resolve 함수를 호출합니다.
// '아메리카노 준비 완료!'라는 메시지와 함께 resolve 함수를 호출합니다.
resolve('아메리카노 준비 완료!');
}, 3000); // 3초 후에 커피 제조가 완료됩니다.
});
// 프로미스 객체 사용
coffeeOrder
// then 메서드를 사용하여 커피가 성공적으로 제조되었을 때의 처리를 작성합니다.
.then(coffee => {
// 커피 제조가 성공적으로 완료되면 고객에게 제공될 커피의 이름을 출력합니다.
// coffee 매개변수에는 resolve 함수에서 전달한 '아메리카노 준비 완료!'가 전달됩니다.
console.log(coffee); // '아메리카노 준비 완료!'가 출력됩니다.
})
// catch 메서드를 사용하여 커피 제조에 실패했을 때의 처리를 작성합니다.
.catch(error => {
// 커피 제조가 실패하면 에러 메시지를 출력합니다.
console.error(error);
});
- React
// src/OrderCoffee.jsx
import React from 'react';
function OrderCoffee({ coffee, time }) {
// 프로미스 객체 생성
const coffeeOrder = new Promise((resolve, reject) => {
console.log(`${coffee}를 만드는 중...`);
setTimeout(() => {
console.log(`${coffee}가 만들어졌습니다.`);
resolve('아메리카노 준비 완료!'); // 성공적으로 커피를 만들었을 때 resolve 함수 호출
}, time);
});
// 프로미스 객체 사용
coffeeOrder
// 성공적으로 커피를 만들었을 때 실행할 코드
.then(coffee => {
console.log(coffee);
})
// 커피를 만들지 못했을 때 실행할 코드
.catch(error => {
console.error(error);
});
return <div>{coffee}</div>;
}
export default OrderCoffee;
// src/App.js
import React from 'react';
import OrderCoffee from './OrderCoffee';
function App() {
return (
<div>
<OrderCoffee
coffee="아메리카노"
time={4000}
/>
<OrderCoffee
coffee="카페라떼"
time={5000}
/>
<OrderCoffee
coffee="카페모카"
time={6000}
/>
</div>
);
}
export default App;
위 코드는 비동기 작업이 성공적으로 완료되기를 기다렸다가, 완료되면 결과를 처리하는 전형적인 패턴을 보여줍니다. 프로미스를 사용함으로써 비동기 작업의 성공 또는 실패에 따른 처리를 체계적이고 가독성 좋게 구현할 수 있습니다.
- 50% 확률로 성공 또는 실패를 시뮬레이션하는 코드
- Vanilla JavaScript
const coffeeOrder = new Promise((resolve, reject) => {
setTimeout(() => {
// 50% 확률로 성공 또는 실패를 시뮬레이션
if (Math.random() > 0.5) {
resolve('아메리카노 준비 완료!');
} else {
reject('커피를 준비하지 못했습니다. 죄송합니다.');
}
}, 3000);
});
coffeeOrder
.then(coffee => {
console.log(coffee);
})
.catch(error => {
console.error(error);
});
- React
// src/OrderCoffee.jsx
import React from 'react';
function OrderCoffee({ coffee, time }) {
const coffeeOrder = new Promise((resolve, reject) => {
// 프로미스 객체 생성
console.log(`${coffee}를 만드는 중...`);
setTimeout(() => {
if (Math.random() > 0.5) {
resolve('아메리카노 준비 완료!');
} else {
reject('커피를 준비하지 못했습니다. 죄송합니다.');
}
}, time);
});
coffeeOrder
.then(coffee => {
console.log(coffee);
})
.catch(error => {
console.error(error);
});
return <div>{coffee}</div>;
}
export default OrderCoffee;
뉴스 API 데이터 가져오기
- 뉴스 API 키 발급
- News API에 접속하여 회원가입을 한다.
- API Key를 발급받는다.
- Fetch API로 데이터 가져오기
// src/News.js
import React, { useEffect, useState } from 'react';
function News() {
const [news, setNews] = useState([]);
useEffect(() => {
fetch('https://newsapi.org/v2/top-headlines?country=kr&apiKey=API_KEY')
.then(response => response.json())
.then(data => {
console.log(data);
setNews(data.articles);
})
.catch(error => console.error(error));
}, []);
return (
<div>
<h1>뉴스</h1>
<ul>
{news.map((article, index) => (
<li key={index}>
<a
href={article.url}
target="_blank"
rel="noreferrer"
>
<img
src={article.urlToImage}
alt=""
/>
{article.title}
</a>
</li>
))}
</ul>
</div>
);
}
export default News;
- API Key 숨기기
API Key는 노출되면 안 되는 중요한 정보이므로, API Key를 숨기기 위해 .env 파일을 사용한다. 적용 후 서버를 재시작해야 한다.
- 프로젝트 루트 디렉토리에 .env 파일에서 환경 변수를 설정한다.
- .env 파일에 API Key를 저장한다.
// .env
REACT_APP_NEWS_API_KEY=API_KEY
- .env 파일에 저장한 API Key를 process.env.REACT_APP_NEWS_API_KEY로 시작하는 이름으로 사용한다.
// src/News.js
import React, { useEffect, useState } from 'react'
function News() {
const [news, setNews] = useState([])
useEffect(() => {
// .env 파일에 저장한 API Key를 사용
fetch(`https://newsapi.org/v2/top-headlines?country=kr&apiKey=${process.env.REACT_APP_NEWS_API_KEY}`)
(...)
}, [])
return (
(...)
)
}
export default News
4. async/await로 비동기 처리하기
async/await는 프로미스를 더 쉽게 사용할 수 있도록 해주는 ES8(ECMAScript 2017)의 문법으로 비동기 처리를 더 간결하게 작성할 수 있다.
- async : 함수 앞에 async 키워드를 붙이면, 해당 함수는 항상 프로미스를 반환한다.
- await : await 키워드는 async 함수 내부에서만 사용할 수 있으며, 프로미스가 처리될 때까지 기다린 후 결과를 반환한다.
// src/News.js
import React, { useEffect, useState } from 'react'
function News() {
const [news, setNews] = useState([])
useEffect(() => {
// async/await로 비동기 처리하기
const fetchData = async () => {
// try: 정상적으로 실행되는 코드
// catch : 에러가 발생했을 때 실행할 코드
// fetch 함수를 사용하여 뉴스 데이터를 가져옵니다.
try {
const response = await fetch(`https://newsapi.org/v2/top-headlines?country=kr&apiKey=${process.env.REACT_APP_NEWS_API_KEY}`) // API Key를 사용
const data = await response.json() // JSON 형태로 변환
console.log(data) // 데이터 확인
setNews(data.articles) // 뉴스 데이터를 상태로 저장
} catch (error) {
console.error(error)
}
}
fetchData()
}, [])
return (
(...)
)
}
export default News
5. axios로 데이터 가져오기
axios는 브라우저와 Node.js를 위한 Promise 기반 HTTP 클라이언트로, 비동기 방식으로 HTTP 데이터 요청을 수행할 수 있다.
axios를 사용하는 이유는 fetch API보다 더 간결하고 직관적이며, 브라우저 호환성이 더 좋기 때문이다.
- axios 설치
$ npm install axios
- axios로 데이터 가져오기
// src/News.js
import React, { useEffect, useState } from 'react'
import axios from 'axios'
function News() {
const [news, setNews] = useState([])
useEffect(() => {
// axios로 데이터 가져오기
const fetchData = async () => {
try {
const response = await axios.get(`https://newsapi.org/v2/top-headlines?country=kr&apiKey=${process.env.REACT_APP_NEWS_API_KEY}`)
// data 속성에 뉴스 데이터가 들어있음
console.log(response.data)
setNews(response.data.articles)
} catch (error) {
console.error(error)
}
}
fetchData()
}, [])
return (
(...)
)
}
export default News
6. 비동기 처리의 순서
비동기 처리를 할 때, 작업의 순서를 보장하기 위해 async/await를 사용할 수 있다.
// src/News.js
import React, { useEffect, useState } from 'react'
import axios from 'axios'
function News() {
const [news, setNews] = useState([])
useEffect(() => {
const fetchData = async () => {
try {
// 첫 번째 요청
const response1 = await axios.get(`https://newsapi.org/v2/top-headlines?country=kr&apiKey=${process.env.REACT_APP_NEWS_API_KEY}`)
console.log(response1.data)
setNews(response1.data.articles)
// 두 번째 요청
const response2 = await axios.get(`https://newsapi.org/v2/top-headlines?country=us&apiKey=${process.env.REACT_APP_NEWS_API_KEY}`)
console.log(response2.data)
} catch (error) {
console.error(error)
}
}
fetchData()
}, [])
return (
(...)
)
}
export default News
위 코드를 실행하면, 한 번에 두 개의 요청을 보내고, 첫 번째 요청이 완료된 후 두 번째 요청이 실행된다.
7. Promise.all로 여러 개의 프로미스 처리하기
Promise.all은 여러 개의 프로미스를 동시에 처리할 수 있는 메서드로, 모든 프로미스가 성공적으로 처리되었을 때 결과를 반환한다.
// src/News.js
import React, { useEffect, useState } from 'react'
import axios from 'axios'
function News() {
const [news, setNews] = useState([])
useEffect(() => {
const fetchData = async () => {
try {
// Promise.all로 여러 개의 프로미스 처리하기
const [response1, response2] = await Promise.all([
axios.get(`https://newsapi.org/v2/top-headlines?country=kr&apiKey=${process.env.REACT_APP_NEWS_API_KEY}`),
axios.get(`https://newsapi.org/v2/top-headlines?country=us&apiKey=${process.env.REACT_APP_NEWS_API_KEY}`)
])
console.log(response1.data)
console.log(response2.data)
} catch (error) {
console.error(error)
}
}
fetchData()
}, [])
return (
(...)
)
}
export default News
위 코드를 실행하면, 두 개의 요청을 동시에 보내고, 두 요청이 모두 완료되면 결과를 반환한다.
'Front > JavaScript' 카테고리의 다른 글
변수(Variable) - javascript 기본 (0) | 2024.06.23 |
---|---|
javascript 핵심 요약 (1) | 2024.05.30 |
모듈(Module) - javascript 기본 (0) | 2023.10.22 |
표준 내장 객체 - 객체(object) - javascript 기본 (0) | 2023.10.22 |
표준 내장 객체 - 배열(array) - javascript 기본 (0) | 2023.10.22 |