장점: 설계 간단, 직관적
단점: 결과가 주어질때까지 계속 하나의 요청에 대한 응답값을 대기해야함
장점: 요청에 따른 결과를 기다리지 않고 다른 작업 수행 가능
단점: 동기식보다 설계 복잡
이러한 점을 봤을 때, 당연히 비동기가 좋지 않냐는 생각이 들것이다. 하지만 하나의 예시를 들어보자.
- 빨래를 세탁기에 돌린다.
- 완성된 빨래를 건조기에 돌린다.
- 건조가 완성된 옷들을 정리하여 옷장에 넣는다.
위와 같은 순서로 집안일을 할때, 비동기식으로 진행해보자.
- 빨래를 세탁기에 돌린다. → 큰 값이므로 백그라운드로 이동
- 빨래를 건조기에 돌린다. → 세탁기가 다 돌아가지 않는 상태로, 건조기에 돌릴 옷이 존재X
- 세탁기 결과물 없이 건조기가 돌아감
- 에러 발생 or 건조기 돌려도 결과물이 존재X
이와 같은 에러가 발생할 수 있다. 그래서 작업에 따라 동기식으로 진행할지, 비동기식으로 진행할지 판단할 필요가 있다.
위와 같은 문제로 인해 나온 비동기처리 방식이 있다.
1. 콜백함수
2. promise (resolve, reject)
3. then & catch
4. async & await
콜백함수: 나중에 실행되는 함수로, 비동기 작업이 끝난 후 실행되는 함수
setTimeout((arg)=>{
console.log(arg)
setTimeout((arg)=>{
console.log(arg)
setTimeout((arg)=>{
console.log(arg)
setTimeout((arg)=>{
console.log(arg)
}, 1000, "네번째 콜백")
}, 1000, "세번째 콜백")
}, 1000, "두번째 콜백")
}, 1000, "첫번째 콜백")
하지만 연속적인 비동기 함수의 호출과 처리는 수많은 callback 함수를 필요로 하고, 이로 인해 가독성이 안좋아진다. 이러한 문제를 Callback Hell
이라고 부른다.
이러한 Callback Hell의 문제로 promise 객체가 나왔다.
promise 객체는 콜백함수의 callback hell을 해결하기 위해 나왔다. callback과 promise를 통해 짜인 코드를 비교해보자.
Callback
/* callback */
function add10(a, callback){
setTimeout(() => callback(a + 10), 100);
}
add10(5, res => {
add10(res, res => {
add10(res, res => {
console.log(res); //35
}); // Callback Hell...
});
});
Promise
/* promise */
function add20(a){
return new Promise(resolve => setTimeout(() => resolve(a + 20), 100));
}
add20(5)
.then(add20)
.then(add20)
.then(console.log); //65
Promise는 Callback과 달리 결과를 값으로 받아서 저장할 수 있다. 즉, Promise는 반환만 하면 되며, 따로 Callback 함수를 받을 필요가 없다. 그래서 Promise는 결과 그 자체를 값으로 받기 때문에, 연속으로 실행하는 코드에선 then()
을 이용한다.
await
는 async
가 붙어있는 함수 내부에서만 사용할 수 있으며 비동기 함수가 리턴하는 Promise로부터 결과값을 추출해준다. 즉, await
를 사용하면 일반 비동기처리처럼 바로 실행이 다음 라인으로 넘어가는 것이 아니라 결과값을 얻을 수 있을때까지 기다려준다.
async function 함수명() {
await 비동기_처리_메서드_명();
}