비동기 작업의 이해
동기 vs 비동기

동기(synchronous)
- 동기는 데이터의 요청과 결과가 한 자리에서 동시에 일어나는것을 말함
- 요청을 하면 시간이 얼마나 걸리던지 요청한 자리에서 결과가 주어져야 함
비동기(Asynchronous)
- 비동기는 동시에 일어나지 않음
- 요청한 결과는 동시에 일어나지 않을 것이라는 약속
동기와 비동기의 장단점
동기
- 장점 : 설계가 매우 간단하고 직관적
- 단점 : 결과가 주어질 때까지 아무것도 못하고 대기해야함
비동기
- 장점 : 요청에 따른 결과가 반환되는 시간 동안 다른 작업을 수행할 수 있음 (자원을 효율적으로 사용 가능)
- 단점 : 동기식보다 설계가 복잡
웹 애플리케이션을 만들다 보면 처리할 때 시간이 걸리는 작업이 있다. ( 예 : 서버쪽 데이터가 필요해 Ajax 기법을 사용하여 서버의 API를 호출하는 경우, setTimeout 함수를 사용하여 특정 작업을 예약할 때 )
콜백 함수
1초에 걸쳐서 10, 20, 30, 40과 같은 형태로 숫자를 더해서 반환 해주고 싶은 경우
<code />
function increase(number, callback) {
setTimeout(() => {
const resuilt = number + 10;
if (callback) {
callback(result);
}
}, 1000)
}
increase(0, result => {
console.log(result);
});
console.log('작업 시작');
increase(0, result => {
console.log(result);
increase(0, result => {
console.log(result);
increase(0, result => {
console.log(result);
increase(0, result => {
console.log(result);
});
});
});
});
실행 결과

이러한 콜백 중첩은 가독성이 나빠짐 ⇒ 이러한 형태의 코드를 ‘콜백 지옥' 이라고 부름 (지양해야 할 코드)
Promise
Promise는 콜백 지옥 같은 코드가 형성되지 않게 하는 방안으로 ES6에 도입된 기능
<code />
function increase(number) {
const promise = new Promiose((resolve, reject) => {
// resolve는 성공, reject는 실패
setTimeout(() => {
const result = number + 10;
if (result > 50) {
// 50보다 높으면 에러 발생시키기
const e = new Error('NumberTooBig');
return reject(e);
}
resolve(result); // number 값에 +10 후 성공 처리
}, 1000);
});
return promise;
}
increse(0)
.then(number => {
// Promise에서 resolve된 값은 .then을 통해 받아 올 수 있음
console.log(number);
return increase(number); // Promise를 리턴하면
})
.then(number => {
// 또 .then으로 처리 가능
console.log(number);
return increase(number);
})
.then(number => {
console.log(number);
return increase(number);
})
.then(number => {
console.log(number);
return increase(number);
})
.then(number => {
console.log(number);
return increase(number);
})
.catch(e => {
// 도중에 에러가 발생한다면 .catch를 통해 알 수 있음
console.log(e);
});
- 함수를 여러 번 감싸는 것이 아니라 .then을 사용하여 그 다음 작업을 설정하기 때문에 콜백 지옥이 형성되지 않음
async/await
async/await는 Promise를 더욱 쉽게 사용할 수 있도록 해 주는 ES2017(ES8)문법
이 문법을 사용하려면 함수의 앞부분에 async 키워드를 추가하고, 해당 함수 내부에서 Promise 앞부분에 await 키워드를 사용
<code />
function increase(number) {
const promise = new Promiose((resolve, reject) => {
// resolve는 성공, reject는 실패
setTimeout(() => {
const result = number + 10;
if (result > 50) {
// 50보다 높으면 에러 발생시키기
const e = new Error('NumberTooBig');
return reject(e);
}
resolve(result); // number 값에 +10 후 성공 처리
}, 1000);
});
return promise;
}
async function runTasks() {
try { // try/catch 구문을 사용하여 에러를 처리합니다.
let result = await increase(0);
console.log(result);
result = await increase(result);
console.log(result);
result = await increase(result);
console.log(result);
result = await increase(result);
console.log(result);
result = await increase(result);
console.log(result);
result = await increase(result);
console.log(result);
result = await increase(result);
console.log(result);
} catch (e) {
console.log(e);
}
}
axios로 API 호출해서 데이터 받아 오기
axios는 현재 가장 많이 사용되고 있는 자바스크립트 HTTP 클라이언트이다. 이 라이브러리의 특징은 HTTP 요청을 Promise 기반으로 처리한다는 점이다.
axios
axios 요청(request) 파라미터 옵션
<code />
/* axios 파라미터 문법 예시 */
axios({
method: "get", // 통신 방식
url: "www.naver.com", // 서버
headers: {'X-Requested-With': 'XMLHttpRequest'} // 요청 헤더 설정
params: { api_key: "1234", langualge: "en" }, // ?파라미터를 전달
responseType: 'json', // default
maxContentLength: 2000, // http 응답 내용의 max 사이즈
validateStatus: function (status) {
return status >= 200 && status < 300; // default
}, // HTTP응답 상태 코드에 대해 promise의 반환 값이 resolve 또는 reject 할지 지정
proxy: {
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
}, // proxy서버의 hostname과 port를 정의
maxRedirects: 5, // node.js에서 사용되는 리다이렉트 최대치를 지정
httpsAgent: new https.Agent({ keepAlive: true }), // node.js에서 https를 요청을 할때 사용자 정의 agent를 정의
})
.then(function (response) {
// response Action
});
axios 응답(response) 데이터
<javascript />
axios({
method: "get", // 통신 방식
url: "www.naver.com", // 서버
})
.then(function(response) {
console.log(response.data)
console.log(response.status)
console.log(response.statusText)
console.log(response.headers)
console.log(response.config)
})
<code />
response.data: {}, // 서버가 제공한 응답(데이터)
response.status: 200, // `status`는 서버 응답의 HTTP 상태 코드
response.statusText: 'OK', // `statusText`는 서버 응답으로 부터의 HTTP 상태 메시지
response.headers: {}, // `headers` 서버가 응답 한 헤더는 모든 헤더 이름이 소문자로 제공
response.config: {}, // `config`는 요청에 대해 `axios`에 설정된 구성(config)
response.request: {}
// `request`는 응답을 생성한 요청
// 브라우저: XMLHttpRequest 인스턴스
// Node.js: ClientRequest 인스턴스(리디렉션)
Axios
브라우저와 node.js를 위한 Promise 기반 HTTP 클라이언트 라이브러리 Axios는 브라우저와 node.js를 위한 간단한 Promise 기반 HTTP 클라이언트입니다. Axios는 확장 가능한 인터페이스를 가진 작은 패키지로
axios-http.com
정리
리액트 컴포넌트에서 API를 연동하여 개발할 때 절때 잊지 말아야 할 유의 사항
- useEffect에 등록하는 함수는 async로 작성하면 안됨 (대신 함수 내부에 async 함수를 따로 만들어 주어야 함)
<code />
// useEffect 를 async await 로 만든 예
useEffect(async () => {
const data = await fetchUser(userId);
setUser(data);
}, [userId]);
async await 함수는 프로미스 객체를 반환하므로 부수효과 함수가 될 수 없다.
부수 효과 함수는 함수만 반환 할 수 있으며, 반환된 함수는 부수 효과 함수가 호출되기 직전과 컴포넌트가 사라지기 직전에 호출된다.
부수 효과 함수란?
- Side Effect (부수 효과)를 발생시키는 함수
- Side Effect란?
- 사이드 이펙트란 사전적 의미로 원래의 목적과 다르게 다른 효과가 발생하는 것
- 리액트에서 사이드 이펙트란 변경이나 효과가 일어날 때 다른 효과가 발생할 수 있도록 설정하는 것
<code />
// 함수 내부에 async 함수를 따로 만든 예
useEffect(() => {
async function fetchAndSetUser() { // 1
const data = await fetchUser(userId);
setUser(data);
}
fetchAndSetUser(); // 2
},[userId]);
- useEffect 내에서 async await 함수를 만들고
- 그 함수를 바로 호출한다.
'React' 카테고리의 다른 글
[React] 리덕스 라이브러리 (0) | 2023.07.01 |
---|---|
[React] Context API (0) | 2023.06.30 |
[React] immer (0) | 2023.06.28 |
[React] 컴포넌트 스타일링 (0) | 2023.06.27 |
[React] 컴포넌트 스타일링 (0) | 2023.06.22 |