본문 바로가기

React/이론

[React] 비동기 작업(콜백 함수, Promise, async, await)

웹 애플리케이션을 만들다 보면 처리할 때 시간이 걸리는 작업이 있다.

 

예를 들어 웹 애플리케이션에서 서버 쪽 데이터가 필요할 때는 ajax 기법을 사용하여 서버의 API를

호출하여 데이터를 수신한다.

 

이 경우 네트워크 송수신 과정에서 시간이 걸리기 때문에 작업이 즉시 처리되는 것이 아니라, 응답을

받을 때까지 기다렸다가 전달받은 응답 데이터를 처리한다.

 

이 과정에서 해당 작업을 비동기적으로 처리하게 된다.

만약 작업을 동기적으로 처리한다면 요청이 끝날 때까지 기다리는 동안 중지 상태가 되기 때문에

다른 작업을 할 수 없다.

 

그리고 요청이 끝나야 비로소 다음 예정된 작업을 할 수 있다. 하지만 비동기적으로 처리하면

웹 애플리케이션이 멈추지 않기 때문에 동시에 여러 가지 요청을 처리할 수도 있고, 기다리는 과정에

다른 함수를 호출할 수 있다.

 

자바스크립트에서 비동기 작업을 할 때 가장 흔히 사용되는 방법은 콜백 함수를 사용하는 것이다.

 

1. 콜백함수

콜백 함수는 함수 자체를 인자로 전달하는 함수를 말한다.

 

예를 들어 파라미터 값이 주어지면 1초 뒤에 10을 더해서 반환하는 코드가 있다.

그리고 해당 함수가 처리된 직후 어떠한 작업을 하고 싶다면 아래와 같이 콜백 함수를 활용해 작업한다.

function increase(number, callback) {
	setTimeout(() => {
		const result = number + 10;
		if (callback){
			callback(result);
		} 
	},1000)
}

increase(0, result => {
	console.log(result);
});

위와 같이 1초에 텀을 setTimeout()으로 주고 + 연산이 끝나면 callback의 유무를 확인해 수행중첩해서 구현할 수 있다.

 

console.log("작업 시작");
increase(0, result => {
	console.log(result);
	increase(result, result => {
		console.log(result);
		increase(result, result => {
			console.log(result);
			console.log("작업 완료");
		});
	});
});

console.log("과연 마지막에 호출될까?");

// 결과 
// 작업 시작
// 과연 마지막에 호출될까?
// 10
// 20
// 30
// 작업 완료

 

작업 결과를 보면 순서대로 출력되는 것이 아닌

작업 시작 이후 increase()가 호출되고 기다리지 않고 " 과연 마지막에 호출될까? "가 출력된다.

 

그 후 1초씩 뒤에 숫자가 출력되는 것을 볼 수 있다.

 

함수는 비동기적으로 처리되어 increase () 안에 있는 함수가 모두 완료되기까지 기다리지 않고이렇게 콜백 안에 또 콜백을 넣어서 구현할 수 있는데, 너무 여러 번 중첩되면 코드의 가독성이 나빠진다.

이러한 형식을 " 콜백 지옥" 이라고 부른다.

 

2. Promise

Promise는 콜백 지옥과 같은 코드가 형성되지 않게 하는 방안으로 도입된 ES6에 도입된 기능!

 

콜백 함수에서 본 코드를 한번 Promise로 구현해보자!

function increase(number) {
	const promise = new Promise((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;
}

increase(0)
	.then(number => {
		// Promise에서 resolve된 값은 .then을 통해 받아 올 수 있음
		console.log("여기다",number);
		return increase(number);
	})
	.then(number => {
		// 또 다시 .then으로 처리 가능하다.
		console.log(number);
		return increase(number);
	})
	.then(number => {
		console.log(number);
		return increase(number);
	})
	.catch(e => {
		// 도중에 에러가 발생한다면 .catch를 통해 알 수 있음
		console.log(e);
	});

여러 작업을 연달아 처리한다고 해서 함수를 여러 번 감싸는 것이 아니라 .then을 사용하여

그다음 작업을 설정하기 때문에 콜백 지옥이 형성되지 않는다!

3. async / await 

async/await 는 Promise를 더욱 쉽게 사용할 수 있도록 해 주는 ES2017(ES8) 문법이다.

 

이 문법을 사용하려면 함수의 앞부분에 async 키워드를 추가하고,

해당 함수 내부에서 Promise 앞부분에 await 키워드를 사용한다.

 

이렇게 하면 Promise가 끝날 때까지 기다리고, 결과 값을 특정 변수에 담을 수 있다.

 

function increase(number) {
	const promise = new Promise((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{
		let result = await increase(0);
		console.log(result);
		
		result = await increase(result);
		console.log(result);
		
		result = await increase(result);
		console.log(result);
	}
	catch(e){
		console.log(e);
	}
}

 

반응형

'React > 이론' 카테고리의 다른 글

[React] import React from 'react'는 어디에 쓰일까?  (1) 2022.04.17
[React] Virtual DOM  (2) 2022.03.12
[React] ref란?  (0) 2022.02.08
[React] Hook  (0) 2022.02.08
[React] React-lifecycle  (0) 2022.02.08