자바스크립트는 싱글 스레드 프로그래밍 언어이기 때문에 비동기 처리가 필수 적이다. 비동기 처리는 그 결과가 언제 반환될지 알수 없기 때문에 동기식으로 처리하는 기법들이 사용되어야 한다. 대표적으로 setTimeout
이 있고, callback
과 promise
가 있다. 세 가지 모두 비동기 코드를 동기식으로 작성하는데 풀륭한 기법들이지만, 모두 약간의 문제점을 가지고 있다. 하지만 async & await
는 이런 문제를 해결함과 동시에 그 사용법에서 있어서도 훨씬 단순해졌다.
특정 시간 동안 기다렸다가 이후 첫번째 파라미터의 함수를 실행하는 방식이다.
let first = 10,
second = 20,
result = 0
function add(x,y){
return x + y
}
setTimeout(()=>{
result = add(first,second)
console.log(result) // 40
},1000);
first = 20;
왜 30
이 아닌 40
이 찍힐까?
자바스크립트는 각각의 task
를 큐에 적재해두고 순서대로 처리한다. 최초의 task
는 스크립트 파일 자체 이다. 이 첫번째 task
내에 setTimeout
은 별도의 task
를 생성하고 첫번째 task
가 종료되길 기다린다. 첫번째 task
인 스크립트의 실행이 끝나면 비로소 setTimeout
의 함수를 실행할 준비를 한다. 즉 first의 값은 초기에 10
이였지만 첫번째 스크립트가 종료되면 20
이 되기 때문에 결과적으로 result = 40
이 된다.
let first = 10,
second = 20,
result = 0
function add(x,y){
return x + y
}
function getResult(callback){
setTimeout(()=>{
result = add(first,second)
console.log(result) // 30
callback() // 콜백함수를 이용한다.
},1000);
}
getResult(()=>{
first = 20;
})
위와 같이 callback
함수를 사용하면 비동기 코드를 동기식으로 작성할수 있다.
callback 함수란 호출하는 함수가 호출되는 함수로 전달하는 함수를 말하며 이때 callback 함수의 제어권은 호출되는 함수에게 있다. callback 함수는 setTimeout
함수와 같은 비동기 코드를 동기식으로 처리하기 위해 사용된다.
callback이 직관적이고 이해가 어렵지는 않지만, 여러개의 callback을 연달아 사용하게 되면 에러가 발생할 가능성이 높고, 코드의 가독성도 떨어지게된다.
function goWork(time1, timeStartWork) {
wakeUp(time1, function (time2) {
takeSubway(time2, function(time3) {
takeOffSubway(time3, function(time4) {
arriveWork(time4, function(arrivalTime) {
if (arrivalTime > timeStartWork) {
fire();
}
}
}
}
}
}
callback은 비동기 코드를 동기적으로 만드는데 확실한 방법이긴 하지만 남발하게 되면 가독성이 크게 떨어지고 코드의 복잡성도 크게 증가하게 된다. 또한 callback의 호출에 대한 제어권이 다른 함수들에게 넘어가 버리기 때문에 각 콜백함수가 언제 어떻게 몇번 실행되는지 확신 할 수 없다.
어떤 작업이 성공했을 때(resolve
), promise객체의 then()
함수에 넘겨진 파라미터를 단 한번만 호출하겠다는 약속이다. callback의 경우 제어권이 호출되는 함수로 넘어가 버리기 때문에 신뢰성이 다소 떨어지지만 promise는 함수 실행이 성공했을때 then()
함수이 파라미터가 단 한번만 호출되기 때문에 함수를 호출하는 입장에서 확신을 가지고 코드를 작성할수 있다.
또한 실패 했을 경우 (reject)에도 catch()
함수를 통해서 실패 이후의 작업을 처리할 수 있다.
function goWork(time1, timeStartWork) {
return wakeUp(time1)
.then(time2 => tackSubway(time2))
.then(time3 => takeOffSubway(time3))
.then(time4 => arriveWork(time4))
.then(arrivalTime => {
if (arrivalTime > timeStartWork) {
fire()
}
})
}
callback보다는 훨씬 가독성이 높아졌다.
function 키워드 앞에 async
만 붙여주면 되고 , 비동기로 처리되는 부분 앞에 await만 붙여주면 된다. 다만, 몇 가지 주의 점이 있다면 await
뒷부분은 반드시 promise
를 반환해야 한다는 것과 async function
자체도 promise를 반환한다는 것이다.
async function goWork(time1, timeStartWork) {
const time2 = await wakeUp(time1)
const time3 = await takeSubway(time2)
const time4 = await takeOffSubway(time3)
const arrivalTime = await arriveWork(time4)
if (arrivalTime > timeStartWork) {
fire()
}
}
훨씬더 직관적인 코드이다.