[패스트캠퍼스 수강 후기] 프론트엔드 인강 100% 환급 챌린지 15회차 미션 - 28강 비동기처리(callback, promise)
비동기 처리란?
동기적 처리는 한 작업이 끝날때까지 다른 작업들은 준비상태로 있기 때문에 대기시간을 잡아먹는다. 반면 비동기적 처리는 동시에 여러가지의 작업을 처리할 수 있어서 대기시간이 없다. 그럼 코드로 예시를 한번 보도록 하자.
function work(){
const start = Date.now();
for (let i = 0; i < 1000000000; i++){
}
const end = Date.now();
console.log(end - start + 'ms');
}
work();
console.log('다음작업'); //1067ms, 다음작업 반환.
지금 위의 코드는 work가 1067ms 실행되고 나서 다음작업이 실행되는 것을 보여주는 코드다. 여기서 setTimeout을 사용하면 for문이 돌아가는동안 다음작업을 먼저 실행시킬 수 있다.(= 비동기적 처리)
function work(){
setTimeout(() => {
const start = Date.now();
for (let i = 0; i < 1000000000; i++){
}
const end = Date.now();
console.log(end - start + 'ms');
}, 0);
}
console.log('작업시작');
work();
console.log('다음작업');
//작업시작, 다음작업, 1067ms 순서대로 반환.
callback
요것을 callback을 활용해 순서를 좀더 명확히 보도록 해보자.
function work(callback){
setTimeout(() => {
const start = Date.now();
for (let i = 0; i < 1000000000; i++){
}
const end = Date.now();
console.log('work 도는 중');
callback(end - start);
}, 0);
}
console.log('작업시작'); //작업시작
work((ms) => {
console.log(`작업이 ${ms}만에 끝났어요!`);
});
console.log('다음작업'); //work가 도는 동안 먼저 실행.
위의 사진과 같이 나오는 것을 볼 수 있다.
이렇게 callback을 통해 work에서 계산한 값을 다음작업을 위해 꺼내올 수 있다.
이런 비동기적 처리가 필요한 작업은 무엇이 있을까?
Ajax Web API 요청, 파일읽기, 암호화/복호화의 경우는 요청을 하고 서버에서 응답을 할때까지 대기를 해야하므로 이런 경우 다른 작업을 먼저 실행할 수 있도록 위와 같이 비동기적 처리를 해준다. 혹은 작업을 예약할때, 이 작업은 몇초 뒤에 해야한다 할 경우에도 비동기적으로 setTimeout을 활용해서 처리를 해준다.
비동기적 처리를 할때 위에서 본 것 처럼 callback함수 외에도 promise, async, await 등을 사용하곤 한다. 이를 더 알아보자.
promise
promise는 비동기적 처리를 좀 더 편하게 할 수 있도록 ES6에 도입된 기능이다. 코드가 길어질 경우 callback함수를 쓰다보면 복잡해지고 보기 어려워지곤 했다. 그래서 promise를 라이브러리로 끌어서 사용했었는데 편리하다보니까 ES6에 도입이 되었다. 먼저 callback함수를 많이 쓸경우 코드가 어떻게 더러워지는지 봐보자.
//숫자 n을 파라미터로 받아와서 5번에 걸쳐서 1초마다 1씩 더해서 출력하는 함수를 만들어보자.
function increaseAndPrint(n, callback) {
setTimeout(() => {
const increased = n + 1;
console.log(increased);
if (callback) {
callback(increased);
}
}, 1000);
}
increaseAndPrint(0, (n) => {
increaseAndPrint(n, (n) => {
increaseAndPrint(n, (n) => {
increaseAndPrint(n, (n) => {
increaseAndPrint(n, (n) => console.log('작업끝!'));
});
});
});
});
// 1,2,3,4,5,작업끝 반환
이런 코드를 ‘콜백지옥’이라고 부른다고 한다.ㅎㅎㅎ
이제 promise를 사용해서 콜백지옥을 없애볼 것이다.
먼저 promise안에서의 함수를 알아보자.
const myPromise = new Promise((resolve, reject) => {
//구현... promise는 성공할수도있고 실패할수도있다. 성공할때는 resolve를, 실패할때는 reject를 호출해주면 된다.
setTimeout(() => {
//resolve('result'); //성공하는 상황에선 resolve를 쓰고
reject(new Error()); //실패하는 상황에선 reject를 씀.
}, 1000);
});
myPromise.then((result) => {
//'.then'은 promise가 끝나고 할 작업을 설정.
console.log(result);
})
.catch((e) => {
//error를 잡아낼때는 '.catch'를 쓴다.
console.error(e);
});
promise안에서 성공하는 상황을 만드려면 resolve를, 실패하는 상황을 만드려면 reject를 써준다. 그리고 promise로 만든 변수 뒤에 .then을 붙여주면 promise다음에 할 작업을 설정할 수 있다. promise에서의 error를 잡아낼때는 .catch를 붙여준다.
이제 아까만든 increase함수를 promise로 다시 만들어보자. 이번에는 추가적으로 5이상이 되면 error를 띄우게 해보자.
function increaseAndPrint(n) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const value = n + 1;
if (value === 5) {
const error = new Error();
error.name = "ValueIsFiveError"; //error이름을 설정해줄 수도 있음.
reject(error);
return;
}
console.log(value);
resolve(value);
}, 1000);
});
}
increaseAndPrint(0)
.then(increaseAndPrint)
.then(increaseAndPrint)
.then(increaseAndPrint)
.then(increaseAndPrint)
.then(increaseAndPrint)
.catch((e) => {
console.error(e);
});
이렇게 써주면 아주 간단하게 해결!
실무에서는 언제 쓰는지 역시 잘 모르겠지만 일단은 되게 간단하고 쉬워보인다. 필요할때 블로그에서 와서 다시보고 갖다써야겠다.
근데 promise에 단점이 있다. 다 then으로 이어붙어져 있어서 분기를 나누기에 어렵고 어디에서 에러가 일어났는지 찾기 힘들다는 점이다. 그래서 async랑 await이 있다고 하는데 이부분은 내일 알아보도록 한다!
마치면서
오늘은 여기까지..
시청 영상 28강 1~2까지
프론트엔드 개발 올인원 패키지 with React Online. 👉 https://bit.ly/31Cf1hp
Comments