왼쪽과 오른쪽의 코드를 비교해보자.
왼쪽은 이전 글에서 다루었던 Promise를 사용하여 연쇄적으로 비동기 함수가 호출되는 코드이다.
Promise를 리턴하는 timer()라는 함수가 호출되면 .then()을 통해 콜백함수 function()이 호출되고 이 함수는 다시 Promise 리턴해주는 timer() 함수를 리턴한다.
그러면 Promise를 반환하는 함수를 리턴했기 때문에 다시 .then()을 붙여서 Chaining이 가능해진다.
오른쪽은 이러한 왼쪽의 코드와 완전히 동일하게 동작하는 코드이고, async와 await라는 키워드를 사용하여 동기적인 방식으로 코드를 작성하지만 비동기적 처리를 할 수 있게 해준다.
오른쪽 코드를 살펴보면
비동기적으로 실행되는 함수들의 앞에는 await를 붙여줘야 한다. await가 붙어있는 Promise를 리턴하는 함수들은 반드시 다른 함수의 안에서 실행되어야 하고, 그 함수는 async라는 키워드가 앞에 붙어있어야 한다.
두 방식의 코드를 직접 작성하여 비교해보았다.
먼저 Chaining 방식으로 코드를 작성해보았다.
<script>
function timer(time){
return new Promise(function(resolve){
setTimeout(function(){
resolve(time);
}, time);
});
}
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');
});
</script>
start를 출력하고 1초 뒤, 그 이후 2초 뒤, 그 이후 3초 뒤에 시간을 출력하고 end를 출력하는 코드이다.
이와 똑같이 작동하는 코드를 async, await를 사용하여 작성해보았다.
<script>
function timer(time){
return new Promise(function(resolve){
setTimeout(function(){
resolve(time);
}, time);
});
}
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');
}
run();
</script>
결과는 똑같지만 코드가 더 깔끔해진 느낌이다.
run의 앞뒤로 출력을 하도록 코드를 작성해보자
<script>
function timer(time){
return new Promise(function(resolve){
setTimeout(function(){
resolve(time);
}, time);
});
}
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');
}
console.log('parent start');
run();
console.log('parent end');
</script>
parent start가 출력되고 나면 run() 함수가 실행되고, start가 출력된 뒤, run() 함수가 끝나길 기다리지 않고, 바로 parent end가 먼저 출력이 된다. async가 붙어있는 함수는 비동기 함수가 되기 때문에 병렬적으로 처리가 된다.
그렇다면 parent end를 run()이 끝난 다음에 출력하려면 어떻게 해야 할까?
async가 붙어 있는 함수는 암시적으로 Promise를 리턴한다. 이 말은 곧 위의 run() 함수 앞에도 await를 붙일 수 있다는 것이다.
<script>
function timer(time){
return new Promise(function(resolve){
setTimeout(function(){
resolve(time);
}, time);
});
}
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');
}
async function run2(){
console.log('parent start');
await run();
console.log('parent end');
}
run2();
</script>
run() 함수 앞에 await를 붙여 주고, 앞서 작성한 출력 부분을 run2라는 함수 안에 넣어줬다. run2()함수의 앞에는 async를 붙여주면 run2()도 비동기적으로 처리하는 코드가 된다.
원하는 대로 결과가 출력된 것을 확인할 수 있다.
async await를 쓰는 것 말고도 그냥 .then()을 이어 붙일 수도 있다.
<script>
function timer(time){
return new Promise(function(resolve){
setTimeout(function(){
resolve(time);
}, time);
});
}
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');
}
console.log('parent start');
run().then(()=>{console.log('parent end');})
</script>
어차피 run()함수는 비동기 함수이기 때문에 Promise를 리턴할 것이고, 이 Promise에 .then()을 이어붙여서 사용 가능하다.
'JavaScript' 카테고리의 다른 글
[JavaScript] Promise 직접 만들기 (new Promise) (0) | 2022.05.23 |
---|---|
[JavaScript] 비동기(Asynchronous) - Promise (then, catch) (0) | 2022.05.23 |
[JavaScript] 자바스크립트 Callback (콜백 함수) (0) | 2022.05.21 |