동기와 비동기
- 동기: 실행 중인 태스크가 종료되어야 다음 태스크를 진행할 수 있다. 실행 순서가 보장된다는 장점이 있지만 현재 실행중인 태스크가 종료되기 전까지 다음 태스크가 시작될 수 없다는 단점이 있다.
- 비동기: 실행 중인 태스크가 있는지 없는지에 상관없이 새로운 태스크가 시작될 수 있다. 언제든지 태스크가 실행될 수 있다는 장점이 있지만 실행순서가 보장되지 않는다는 단점이 있다. 예시: 이벤트 핸들러, 타이머, 서버에 요청 응답
자바스크립트에서의 비동기 처리 방법에는 callback / Promise 객체 / async-await 세가지 방법이 있다.
callback
실행 순서가 보장되지 않는 비동기 코드를 순서대로 실행하는 가장 일반적인 방법이다.
function first(callback) {
setTimeout(function() {
console.log("first");
callback();
}, 2000)
}
function second() {
console.log("second");
}
first(() => {
second();
});
// 실행결과
// first
// second
위 예시에서 함수 first는 비동기 함수이다. 콜백을 사용하지 않고 first(); second();
와 같이 실행한다면 의도와는 다르게 함수 second가 먼저 실행될 것이다.
이같은 경우를 방지하기 위해 인자로 함수를 넘겨주는 콜백을 통해 실행 순서를 보장해준다.
콜백에는 치명적인 단점이 하나있다. 콜백이 늘어날 경우 가독성이 심하게 떨어져 디버깅이 힘들어진다는 것이다.
이러한 콜백의 문제를 해결하기 위해 도입된 것이 Promise
이다.
Promise
Promise는 자바스크립트에서 비동기 실행을 동기화하는 구문으로 사용된다. 객체이므로 new 연산자로 인스턴스를 생성할 수 있고 3가지 상태를 가진다.
- 대기 Pending
- 이행 Fulfilled
- 거절 Rejected
Promise 객제가 생성되면 대기 상태가 된다. resolver 함수가 실행되면 이행으로 상태가 변경되고, reject 함수가 실행되면 거절 상태로 변경된다.
resolver 함수가 실행되어 이행 상태가 되면 then()
을 이용하여 처리 결과 값을 받을 수 있다. 또, 거절 상태가 되면 catch()
를 이용하여 결과를 받을 수 있다.
function getData() {
return new Promise(function(resolve, reject) {
resolve('success');
// ...
reject('error')
})
}
// resolve()의 결과 값을 result로 받음
getData().then(function(result) {
console.log(result); // 'success'
})
.catch(function(error) {
console.log(error)
})
Promise를 사용하면 콜백이 많아지더라도 콜백함수를 사용할 때보다 정리된 코드를 작성할 수 있다. 하지만 경우에 따라 잘못 작성할 경우 콜백과 비슷한 결과가 생겨 디버깅이 힘들어질 가능성이 있다. 그래서 여기서 좀 더 개선된 방식이 있는데 async await 구문이다.
async await 구문
async await는 자바스크립트에서 가장 최근에 도입한 비동기 처리 방식이다. 기존의 콜백 방식과 Promise 객체 방식의 단점을 보완했으며 가독성 높은 코드를 작성할 수 있다.
async-await를 사용하면 비동기 처리를 동기 처리 코드와 비슷하게 작성할 수 있다. 비동기 처리를 해야하는 함수를 실행하는 함수 앞에 async
키워드를 붙이고, 비동기 함수 앞에 await
를 붙이면 끝이다. 예외 처리는 try ... catch
구문을 사용하면 된다.
function getData() {
return new Promise(function(resolve, reject) {
resolve('success');
})
}
async function displayData() {
try {
let data = await getData();
console.log(data);
} catch(err) {
console.log(err);
}
}
displayData(); // 'success'
참고