끄적끄적 코딩
article thumbnail

비동기 작업의 이해

동기 vs 비동기

동기(synchronous)

- 동기는 데이터의 요청과 결과가 한 자리에서 동시에 일어나는것을 말함
- 요청을 하면 시간이 얼마나 걸리던지 요청한 자리에서 결과가 주어져야 함

비동기(Asynchronous)

- 비동기는 동시에 일어나지 않음
- 요청한 결과는 동시에 일어나지 않을 것이라는 약속

동기와 비동기의 장단점

동기

  • 장점 : 설계가 매우 간단하고 직관적
  • 단점 : 결과가 주어질 때까지 아무것도 못하고 대기해야함

비동기

  • 장점 : 요청에 따른 결과가 반환되는 시간 동안 다른 작업을 수행할 수 있음 (자원을 효율적으로 사용 가능)
  • 단점 : 동기식보다 설계가 복잡


웹 애플리케이션을 만들다 보면 처리할 때 시간이 걸리는 작업이 있다. ( 예 : 서버쪽 데이터가 필요해 Ajax 기법을 사용하여 서버의 API를 호출하는 경우, setTimeout 함수를 사용하여 특정 작업을 예약할 때 )


콜백 함수

1초에 걸쳐서 10, 20, 30, 40과 같은 형태로 숫자를 더해서 반환 해주고 싶은 경우

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에 도입된 기능

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 키워드를 사용

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) 파라미터 옵션

/* 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) 데이터

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)
})
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

 

Axios

브라우저와 node.js를 위한 Promise 기반 HTTP 클라이언트 라이브러리 Axios는 브라우저와 node.js를 위한 간단한 Promise 기반 HTTP 클라이언트입니다. Axios는 확장 가능한 인터페이스를 가진 작은 패키지로

axios-http.com

 

정리

리액트 컴포넌트에서 API를 연동하여 개발할 때 절때 잊지 말아야 할 유의 사항

  • useEffect에 등록하는 함수는 async로 작성하면 안됨 (대신 함수 내부에 async 함수를 따로 만들어 주어야 함)
// useEffect 를 async await 로 만든 예

useEffect(async () => {
	const data = await fetchUser(userId);
	setUser(data);
}, [userId]);

async await 함수는 프로미스 객체를 반환하므로 부수효과 함수가 될 수 없다.

부수 효과 함수는 함수만 반환 할 수 있으며, 반환된 함수는 부수 효과 함수가 호출되기 직전과 컴포넌트가 사라지기 직전에 호출된다.


부수 효과 함수란?

  • Side Effect (부수 효과)를 발생시키는 함수
  • Side Effect란?
    • 사이드 이펙트란 사전적 의미로 원래의 목적과 다르게 다른 효과가 발생하는 것
    • 리액트에서 사이드 이펙트란 변경이나 효과가 일어날 때 다른 효과가 발생할 수 있도록 설정하는 것

 

// 함수 내부에 async 함수를 따로 만든 예

useEffect(() => {
async function fetchAndSetUser() { // 1
	const data = await fetchUser(userId);
	setUser(data);
   }
   fetchAndSetUser(); // 2
},[userId]);
  1. useEffect 내에서 async await 함수를 만들고
  2. 그 함수를 바로 호출한다.

'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

검색 태그