JavaScript에서 비동기(asynchronous) 호출의 결과값을 반환해야 하는 상황은 매우 자주 발생합니다. 문제를 제대로 이해하려면 먼저 비동기 함수의 동작 방식부터 살펴볼 필요가 있습니다.
예를 들어 foo라는 비동기 함수가 있고, 이 함수는 일정 시간이 지난 후에야 데이터를 제공한다고 가정해 보겠습니다. 이런 비동기 함수는 크게 두 가지 방식으로 결과를 전달할 수 있습니다.
- 콜백(Callback): 데이터가 준비되면 실행될 함수를 인자로 받아 나중에 호출하는 방식
- 프로미스(Promise): 미래에 확정될 값을 담는 객체를 반환하고,
.then()이나await로 결과를 소비하는 방식
대표적인 예로 setTimeout 함수는 콜백을 인자로 받아 지정된 시간이 지난 후에 해당 콜백을 실행합니다. 첫 번째 방식인 콜백 패턴을 사용하면 다음과 같이 코드를 작성할 수 있습니다.
1. 콜백 함수 사용하기
function myFunc(cb) {
setTimeout(() => cb(100), 1000);
}
myFunc((a) => console.log(a));출력 결과
100
위 코드는 setTimeout에 콜백을 전달하여 1000ms(1초) 후에 실행되도록 합니다. 해당 콜백이 실행되는 시점에 전달받은 콜백(cb)이 값과 함께 호출되면서 최종적으로 100이 출력됩니다. 즉, 비동기 작업이 완료되는 순간 외부로 결과를 넘겨주는 구조입니다.
2. 프로미스(Promise) 사용하기
두 번째 방식은 프로미스를 활용하는 것입니다. 비동기 작업을 프로미스로 감싸고, 작업이 완료되면 resolve를 통해 함수의 반환값을 전달합니다. 이후 .then() 메서드를 체이닝하여 콜백을 등록하면 비동기 함수가 반환한 값을 사용할 수 있습니다.
new Promise(resolve => setTimeout(() => resolve(100), 1000))
.then(console.log);출력 결과
100
위 예제에서는 1초 후 프로미스가 100으로 resolve 되고, .then(console.log)에 등록된 콜백이 그 값을 받아 출력합니다. 콜백 방식보다 코드 흐름이 직관적이고, 여러 비동기 작업을 연결할 때 특히 유용합니다.
3. async/await 활용 (ES2017+)
현대 JavaScript에서는 프로미스 위에 더 간결하게 작성할 수 있는 async/await 문법도 널리 사용됩니다. await 키워드를 사용하면 비동기 코드를 동기 코드처럼 읽기 쉬운 형태로 만들 수 있습니다.
function delay(ms, value) {
return new Promise(resolve => setTimeout(() => resolve(value), ms));
}
async function main() {
const result = await delay(1000, 100);
console.log(result);
}
main(); // 100정리하자면, 비동기 호출의 응답을 반환하는 방식은 콜백, 프로미스, async/await 세 가지입니다. 새로운 코드라면 가독성과 에러 처리 측면에서 유리한 프로미스 또는 async/await 방식을 권장합니다.