Callback & Promise
1초마다 로그를 출력하는 동일한 내용의 코드를 콜백함수와 프로미스로 구현했다.
프로미스를 사용함으로서 콜백함수가 중첩되는 현상인 '콜백 지옥'로부터 벗어났다.
// callback hell
timer(1000, function() {
console.log("작업");
timer(1000, function() {
console.log("작업");
timer(1000, function() {
console.log("작업");
});
});
});
// use promise's then
timer(1000)
.then(function() {
console.log("작업");
return timer(1000); // 타이머 실행 후 Promise 객체를 return함
})
.then(function() {
console.log("작업");
return timer(1000);
})(function() {
console.log("작업");
})
await & async
이제 프로미스를 써서 콜백 지옥으로 부턴 벗어났다. 근데 더 읽기 좋은 코드를 만들기 위해 then, function, return도 안 쓰고싶다. 마치 동기적인 코드를 작성하는 것처럼 비동기 코드를 쓸 수 있는 방법은 없을까? 이때 쓸 수 있는 게 await와 async다.
await & async 코드 만들기
1. 비동기 함수 앞에 '이 함수가 실행되길 기다려라'는 뜻의 await를 붙인다.
2. await가 붙은 promise를 반환하는 함수는 반드시 다른 함수 안에서 실행돼야 하며, 그 함수 앞엔 async 키워드를 붙인다.
async function run() {
await timer(1000)
console.log("작업");
await timer(1000)
console.log("작업");
await timer(1000)
console.log("작업");
}
run();
이렇게하면 위 코드와 똑같이 동작하는 코드를 깔끔하게 짤 수 있다.
await의 return 값 사용하기
function timer(time) {
return new Promise(function(resolve) { // 프로미스 생성은 일단 black box로 생각한다
setTimeout(function(){
resolve(time);
}, time);
});
}
// promise code
console.log('start');
timer(1000).then(function(time){
console.log("time:"+time)
return timer(time+1000);
}).then(function(time){
console.log("time:"+time)
return timer(time+1000);
}).then(function(time){
console.log("time:"+time)
// console.log('end'); // start -> time:1000 -> time:2000 -> time:3000 -> end
});
console.log('end'); // start -> end -> time:1000 -> time:2000 -> time:3000
start 로그를 찍고 타이머 함수 실행 후 마지막에 end 로그를 찍고싶지만 현재 코드에선 start 로그, end 로그가 출력된 후 타이머 함수가 실행된다. end 로그를 마지막에 찍으려면 마지막 time 출력 코드 뒤에 end 로그가 있어야 한다. (line 18)
위 코드는 가독성이 떨어지기 때문에 await와 async로 코드를 정리해보면 다음과 같다.
1. timer 함수가 비동기적 코드임을 명시하기 위해 await를 붙인다.
2. await를 붙이면 비동기 함수(timer)의 결괏값(time)을 변수로 받을 수 있다.
3. await 함수를 감싸는 바깥 함수에 async를 붙인다.
// await & async code
async function run() {
console.log('start');
var time = await timer(1000);
console.log("time:"+time);
time = await timer(time+1000);
console.log("time:"+time);
time = await timer(time+1000);
console.log("time:"+time);
console.log('end');
return time
}
console.log(run()); // start -> time:1000 -> time:2000 -> time:3000 -> end
중첩된 await & async
console.log('parent start');
run();
console.log('parent end');
// parent start -> start -> parent end -> time:1000 -> time:2000 -> time:3000 -> end
parent start와 parent end 로그를 출력하고 싶지만, async는 비동기적으로 동작하는 함수기 때문에 parent end가 마지막에 출력되지 않는다. parent end를 마지막에 출력하려면 다음과 같이 바꾼다.
async function run2() {
console.log('parent start');
await run(); // return Promise { <pending> }
console.log('parent end');
}
run2(); // parent start -> start -> time:1000 -> time:2000 -> time:3000 -> end -> parent end
run 함수는 비동기 함수(async)여서 promise를 리턴하기 때문에 앞에 await를 붙일 수 있다. 그리고 다시 함수로 묶어주면 parent end를 마지막에 출력할 수 있다.
console.log('parent parent start');
run2()
console.log('parent parent end');
// parent parent start -> parent start -> start -> parent parent end -> time:1000 -> time:2000 -> time:3000 -> end -> parent end
이번엔 parent parent start와 parent parent end를 출력하고 싶은데 위와 같은 코드면 parent parent end가 마지막에 출력되지 않는다. 따라서 다음과 같이 수정한다.
console.log('parent parent start');
run2().then(function(){
console.log('parent parent end');
})
//parent parent start -> parent start -> start -> time:1000 -> time:2000 -> time:3000 -> end -> parent end -> parent parent end
최상위에선 async를 쓰지 않아도 되니까 then으로 처리한다.
해당 게시글은 생활코딩님의 JavaScript - async & await 강의를 참고해 작성했습니다.
'Etc > Frontend' 카테고리의 다른 글
[JavaScript] 프로미스(Promise)란? (0) | 2023.03.23 |
---|---|
[JavaScript] 콜백 함수(callback function)란? (0) | 2023.03.21 |
내비게이션 바에서 링크를 클릭했을 때 클릭된 내용을 본문에 나타내기 (0) | 2021.08.11 |
07.13 공부일지 - Javascript 2주차 (0) | 2021.07.14 |
07.13 (0) | 2021.07.14 |