웹앱을 만들다보면 처리하는데 시간이 걸리는 작업이 있는데, 서버측에 데이터를 요청하는 작업이 대표적입니다.
동기방식으로 처리해버리면 서버측에서 응답이 오기전에 우리의 웹앱은 멈춰있기때문에 비동기로 작업해야합니다.
프로젝트 시작전에 비동기 처리를 해주는 Promise 와 async/await 를 알아보려합니다.
promise란?
리액트에서 비동기 처리에 활용되는 객체입니다. 주로 웹 서비스를 구현할 때 서버와 원활환 데이터 통신을 위해 사용됩니다.
웹 페이지에서 서버로 데이터를 요청했을 때, 요청한 데이터가 모두 도착하기 전에 웹 페이지에 출력하는것을 방지하는데에 활용합니다.
또한, 비동기로 서버에 요청한 데이터에 순서를 보장할 수 있기때문에, 비동기이지만 동기처럼 순차적으로 실행이 가능합니다.
주로 서버에 데이터요청, 파일 읽기/쓰기, 타이머 등의 작업에 사용합니다.
요약
- 리액트에서 비동기 처리할 때 사용
- 서버에 데이터 요청시, 응답이 끝나기전에 웹페이지에 출력하는것을 방지
- 다중으로 Promise를 연결하여 순서보장, 병렬처리 가능
- 네트워크 요청, 파일 읽기/쓰기, 타이머에 등에 사용

Promise 생성
const myPromise = new Promise((resolve, reject) => {
//...비동기 작업을 수행할 코드
})
Promise 는 new 연산자로 생성합니다. ( 클래스의 인스턴스라는 뜻이겠죠. )
Promise 인스턴스는 하나의 인자를 가지며, 그 인자는 주로 함수가 사용됩니다. 다른 promise 의 결과 등도 인자로 넘길 수 있습니다.
인자로 전달되는 함수는 2개의 매개변수를 가지며, 첫번째는 성공시 반환할 함수, 두번째는 실패시 반환할 함수가 됩니다.
// Promise 생성
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
//0.5를 기준으로 성공과 실패를 분기처리
const randomNumber = Math.random();
if (randomNumber < 0.5) {
resolve(`성공! 랜덤 숫자: ${randomNumber}`);
} else {
reject(`실패! 랜덤 숫자: ${randomNumber}`);
}
}, 1000); // 1초 후에 작업을 완료
});
// Promise 사용: 성공 및 실패 처리
myPromise
.then((결과) => { // 성공적으로 완료된 경우
console.log(결과);
//`성공! 랜덤 숫자: ${randomNumber}`)
})
.catch((에러) => { // 실패한 경우
console.error(에러);
//`실패! 랜덤 숫자: ${randomNumber}`
});
Promise 선언중 인자로 들어가는 함수의 매개변수명은 어떤것이든 상관없이 첫번째가 성공, 두번째가 실패로 정해져있습니다.
그렇지만 일반적으로는 resolve(성공), reject(실패) 로 주로 사용됩니다.
Poromise 객체가된 myPromise 상수는 .연산자로 접근이 가능합니다.
.then((res)=>{console.log(res)})
//Promise(resolve,reject) 중 resolve 값 취득
.catch((err)=>{console.log(err)})
//Promise(resolve,reject) 중 reject 값 취득
.then 함수는 비동기처리 성공시, 콜백함수로 성공된 값에 접근할 수 있습니다.
.catch 함수는 비동기처리 실패시, 콜백함수로 실패한 값에 접근할 수 있습니다. then 의 체이닝으로 여러번의 비동기 처리를 하던중 중간에 비동기 처리가 실패하면 바로 .catch 가 실행됩니다.
promise 체이닝 기술을 이용하면 비동기 작업을 순차적으로 처리하여 순서의 보장을 받을 수 있습니다.
// Promise 생성 및 체이닝
const firstPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("첫 번째 Promise 완료");
}, 1000);
});
const secondPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("두 번째 Promise 완료");
}, 1500);
});
firstPromise
.then((result) => {
console.log(result);
return secondPromise; // 첫 번째 Promise가 이행되면 두 번째 Promise를 반환
})
.then((result) => {
console.log(result);
console.log("모든 Promise 체이닝이 완료되었습니다.");
});
Promise를 더욱 쉽게 사용할 수 있도록 해주는 ES8 문법입니다.
Async 예약어를 사용하여 함수가 Promise를 반환하게 해줍니다. Promise의 .then .catch 처럼 후속처리 메서드 없이 Promise 결과를 반환할 수 있습니다.
//일반 함수
function Async(){
return 'Async'
}
//async 키워드를 붙힌 함수
async function helloAsync(){
return 'hello Async'
}
----------------------------------------------
//화살표 함수
const hello = () => {
return "func";
};
const asyncHello = async () => {
return "async";
};
async 키워드로 선언한 함수는 Promise 를 반환합니다.

Promise 를 반환한다는 말은 .then , .catch 로 성공, 실패시 값을 취득할 수 있다는 뜻입니다.
asyncHello().then((res) => {
console.log(res); // 'async'
});
.then 메서드를 실행하니, 성공시에 async를 사용한 함수의 return 값을 취득할 수 있었습니다.
즉, Promise 에서의 resolve의 결과값과 같다는 말입니다.
Ayncs 내부에서 사용 가능하며, Await 예약어를 사용한 Promise 를 반환하는 함수는 해당 함수의 작동이 완료될때까지 다음 코드라인을 진행하지 않고 기다립니다.
예제
const delay = (ms) => {
return new Promise((resolve)=>{
setTimeout(resolve,3000)
//콜백 함수 작성시 단순히 출력만 한다면 축약문법 사용가능
})
}
const helloAsync = async () =>{
// 3초후 'async' 반환
return delay(3000).then(() => {
return "async";
});
}
helloAsync.then((res)=>{console.log(res)}) //'async'
위 경우 delay() 함수가 3초뒤 성공한다는 것을 이용해 helloAsync() 함수의 실행 시간을 컨트롤하고 있습니다.
간단하지만 가독성 면에서 떨어집니다. 특정 함수에 Await 예약어를 사용하면 Await을 사용한 함수가 종료되기 전까지 다음 라인을 실행하지 않는다고 하였었죠? 사용해보겠습니다.
Await 사용
const delay = (ms) => {
return new Promise((resolve)=>{
setTimeout(resolve,3000)
//콜백 함수 작성시 단순히 출력만 한다면 축약문법 사용가능
})
}
const helloAsync = async () =>{
//return delay(3000).then(() => {
//return "async";
//});
// 3초후 'async' 반환
await delay(3000)
return "async";
}
// helloAsync.then((res)=>{console.log(res)});//'async'
const asyncResolve = async () => {
const res = await helloAsync();
console.log(res)
}
asyncResolve() //'async'
비동기 처리를 동기처럼 진행하면서 보다 직관적으로 비동기 처리를 할 수 있게 되었습니다.
예외처리
Promise 의 예외처리는 reject 함수를 반환하면서 .catch 함수로 값을 취득할 수 있었는데요, async/await 문법에서는 어떻게 사용할 수 있을까요?
const Err = async () => {
throw new Error('Err 함수에서 에러가 발생했습니다.');
}
const printConsole = () => {
try {
console.log("try 시작");
Err();
console.log("try 끝");
} catch(err) {
console.error('catch 가 실행되었습니다.');
console.error(err);
} finally {
console.log('finally 가 실행되었습니다.');
}
}
printConsole();
/*
try 시작
try 끝
finally 가 실행되었습니다.
Err 함수에서 에러가 발생했습니다.
*/
비동기함수의 에러는 try..catch 문으로 해결할 수 없습니다. 에러가 발생해도 다음 코드블럭을 진행하기 때문이죠.
이를 해결하기 위해 await을 사용합니다.
const printConsole = async () => {
try {
console.log("try 시작");
await Err();
console.log("try 끝");
} catch(err) {
console.error('catch 가 실행되었습니다.');
console.error(err);
} finally {
console.log('finally 가 실행되었습니다.');
}
}
async 함수 내부에서 try ... catch 문을 사용해서 에러 처리를 하지않으면 async 함수는 에러를 reject하는 프로미스를 반환합니다.
try구문에서 에러가 발생하면 코드의 흐름은 catch문으로 넘어갑니다.