01. 동기 vs 비동기
동기와 비동기 개념
순차적이냐 비순차적이냐의 차이
(1) 동기 처리 (Synchronouse Processing)
- 요청과 그에 따른 응답이 순차적으로 일어나는 방식
- 일의 순서가 중요한 경우 동기 처리
- 처리 순서가 보장되지만, 응답을 기다리는 동안 다른 작업을 수행할 수 없기 때문에 비효율적일 수 있음
(2) 비동기 처리 (Asynchronouse Processing)
- 요청과 그에 따른 응답이 비순차적으로 일어나는 방식
- 요청을 보내고 응답을 기다리지 않고, 다음 작업을 계속 진행합니다.
- 일의 순서가 중요하지 않은 경우, 효율적인 일 처리를 위해 비동기 처리!
예시 코드
function sendTextMessage(message, callback) {
// 메시지를 보내는 비동기 작업을 가정해요.
setTimeout(() => {
console.log("문자 메시지 전송 완료: " + message);
callback(); // 응답이 도착하면 콜백 함수 호출
}, 2000); // 2초 후에 메시지 전송이 완료된다고 가정
}
console.log("메시지 보내기 시작");
sendTextMessage("안녕, 잘 지내?", function () {
console.log("메시지 전송 후 후속 작업 수행");
});
console.log("다른 작업 수행");
// 출력 결과:
// 메시지 보내기 시작
// 다른 작업 수행
// 문자 메시지 전송 완료: 안녕, 잘 지내?
// 메시지 전송 후 후속 작업 수행
02. Promise
Promise 개념
- Promise는 자바스크립트에서 비동기 작업의 완료 또는 실패를 처리하기 위해 사용되는 개념
- 비동기 작업이 성공하거나 실패했을 때 각각의 결과를 처리하는 데 도움
- Promise는 비동기 작업의 결과를 다루기 쉽게 하기 위해 만들어졌으며, 비동기 작업이 끝난 이후에 실행될 콜백을 등록할 수 있는 메서드를 제공
- Promise 객체를 생성하기 위해 Promise 생성자(new Promise)를 사용가능
Promise 등장배경
자바스크립트는 비동기 작업을 처리할 때 콜백 함수를 많이 사용
하지만 콜백 함수를 중첩해서 사용하다 보면 코드가 복잡해지고 가독성이 떨어지는 문제가 발생 => 콜백 지옥
Promise가 없다면
- 콜백 함수의 중첩이 깊어져서 코드를 이해하고 유지보수하기 어려워짐
- 에러 처리가 분산되어 관리가 어렵고, 코드의 흐름을 추적하기 힘들어짐
- 여러 개의 비동기 작업을 순차적으로 처리하거나 병렬로 처리하는 경우 코드가 복잡해짐
Promise의 상태
- 대기(Pending): 초기 상태, 이행되거나 거부되지 않은 상태
resolve나 reject로 인해 다른 상태로 변경되기 전까지의 상태 - 이행(Fulfilled): 비동기 작업이 성공적으로 완료된 상태
resolve로 인해 pending 상태에서 fulfilled 상태로 변경 - 거부(Rejected): 비동기 작업이 실패한 상태
reject로 인해 pending 상태에서 rejected 상태로 변경
Promise 객체는 then, catch, finally 메서드를 통해 이행되거나 거부된 이후의 동작을 정의가능
예시코드 / 활용방법 (React)
직접 Promise 객체 만들기 (with 생성자)
const myPromise = new Promise((resolve, reject) => {
// 비동기 작업을 수행합니다.
if (/* 작업이 성공적으로 완료되면 */) {
resolve("성공 메시지");
} else {
reject("실패 메시지");
}
});
=>
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
// 작업의 성공 여부를 나타내는 변수
// 여기를 true <-> false 변경해가며 테스트해보세요!
const success = true;
if (success) {
// resolve 함수는 Promise 객체의 상태를 이행(fulfilled) 상태로 변경해요.
// resolve 함수 자체는 반환값이 없어요.
// 다만, resolve 함수가 호출되면 그 값이 then 메서드의 callback 함수로 전달돼요.
resolve("작업이 성공적으로 완료되었습니다!");
} else {
// 마찬가지 원리로, reject 함수가 호출되면 그 값이 catch 메서드의 callback 함수로 전달돼요.
reject("작업이 실패했습니다.");
}
}, 2000); // 2초 후에 작업이 완료
});
myPromise
.then((result) => {
console.log(result); // "작업이 성공적으로 완료되었습니다!" 출력
})
.catch((error) => {
console.log(error); // "작업이 실패했습니다." 출력
});
in React
import React, { useEffect, useState } from 'react'
const App = () => {
const [message, setMessage] = useState("타이머시작");
useEffect(() => {
const delay = (ms) => {
const promise = new Promise(resolve => {
setTimeout(resolve, ms);
});
return promise;
};
delay(2000).then(() => {
setMessage("2초 후 메시지가 변경됐습니다.");
});
}, []);
return (
<div>
<h1>{message}</h1>
</div>
)
}
export default App
Promise를 활용해 데이터 가져오기 (with fetct함수)
fetch함수는 Promise 객체를 반환
// (1) 컴포넌트가 마운트될 때 fetch를 사용해 데이터를 비동기적으로 가져옴
// (2) Promise의 then 메서드를 사용해 데이터를 설정
// (3) 에러가 발생하면 catch 메서드를 통해 에러를 처리
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;
여러 비동기 작업을 병렬로 처리
1. 순차처리 (Sequential Processing)
첫 번째 작업이 끝나고나서 그 다음 작업 => 그 다음 작업 끝나고 나서 그 다음 작업 => ...
2. 병렬처리 (Parallel Processing)
요청의 순서와 상관없이 모든 요청이 한 번에 들어가고 모든 요청의 결과를 받으면 처리
Promise.all 메서드를 사용하면 여러 비동기 작업을 병렬로 처리가능
모든 작업이 완료될 때까지 기다린 후, 결과를 한 번에 처리
import React, { useState, useEffect } from "react";
function App() {
const [post, setPost] = useState(null);
useEffect(() => {
Promise.all([
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((response) => response.json()),
fetch("https://jsonplaceholder.typicode.com/posts/2")
.then((response) => response.json()),
]).then(([response1, response2]) => {
console.log("response1 => ", response1)
console.log("response2 => ", response2)
})
}, []);
return <div>{post ? <div>{post.title}</div> : <div>Loading...</div>}</div>;
}
export default App;
async / await
async와 await키워드는 Promise객체를 더욱 간편하게 다룰 수 있도록 도와줌
async함수는 항상 Promise를 반환하며, await키워드는 Promise가 이행될 때까지 기다림
이 방법을 사용하면 비동기 코드를 더 동기 코드처럼 작성할 수 있어 가독성이 향상
async / await 개념
- async 함수
async키워드로 정의된 함수는 항상 Promise를 반환
함수 내부에서 명시적으로 return문으로 값을 반환하면 자동으로 Promise.resolve()를 통해 감싸져서 반환 - await 키워드
await키워드는 Promise가 이행될 때까지 기다리고, 이행된 Promise의 결과를 반환
await는 async함수 내부에서 사용
async / await 필요성
- 가독성 : async / await 구문을 사용하면 비동기 코드를 동기 코드처럼 작성할 수 있어 가독성이 크게 향상
- 에러 처리: try - catch구문을 사용하여 비동기 작업에서 발생하는 오류를 간편하게 처리
- 코드의 간결함: 콜백 지옥이나 체이닝을 피할 수 있어 코드가 간결해집니다.
예시 코드
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"
); // fetch의 결과(Promise)를 response에 담음
const data = await response.json(); // fetch의 결과를 json형식으로 바꿔 data에 저장
setPost(data); // post state를 data로 설정
} catch (error) {
console.error("Error fetching post:", error);
}
};
fetchPost();
}, []);
return <div>{post ? <div>{post.title}</div> : <div>Loading...</div>}</div>;
}
export default App;
'React' 카테고리의 다른 글
React : REST API 예시 (0) | 2024.06.10 |
---|---|
React : HTTP, REST API (0) | 2024.06.10 |
React: Supabase (0) | 2024.05.22 |
React: Router DOM - 2 Dynamic Route, useParams, Outlet (0) | 2024.05.22 |
React: Router DOM - 1 (0) | 2024.05.22 |