
만약 모든 작업이 동기적으로 처리된다면 다음과 같은 문제가 발생합니다.
console.log("작업 1 시작");
// 5초 동안 CPU를 점유하는 무거운 작업 (예시)
let start = Date.now();
while (Date.now() - start < 5000) {
// 5초 대기
}
console.log("작업 1 완료");
console.log("작업 2 시작");
while 루프가 실행되는 5초 동안 브라우저(또는 프로그램)가 완전히 멈춥니다.이러한 블로킹 문제를 해결하기 위해 비동기 처리를 사용합니다.
console.log("작업 1 시작");
// setTimeout: 대표적인 비동기 API. 특정 시간 후에 콜백 함수를 실행하도록 위임합니다.
setTimeout(() => {
console.log("작업 1 완료");
}, 5000);
// setTimeout은 작업을 위임하고 즉시 다음 코드를 실행합니다.
console.log("작업 2 시작");
// 실행 결과:
// 작업 1 시작
// 작업 2 시작
// (5초 후)
// 작업 1 완료
setTimeout은 5초를 기다리는 작업을 브라우저(Web API)에 위임하고, 자신은 즉시 다음 코드인 console.log("작업 2 시작")을 실행합니다. 덕분에 프로그램은 멈추지 않고 다른 작업을 계속할 수 있습니다.
웹 브라우저나 Node.js 환경은 다양한 비동기 처리 API를 제공합니다. 이 API들은 대부분 콜백 함수를 인자로 받아 작업 완료 후 실행을 예약합니다.
setTimeout()지정된 시간(delay)이 지난 후 콜백 함수를 한 번 실행합니다.
setTimeout(callback, delay);callback: 지연 후 실행할 함수delay: 실행을 지연할 시간 (밀리초 단위, 1000ms = 1초)function printMessage(number) {
console.log(number);
}
printMessage(1);
setTimeout(() => {
printMessage(2);
}, 2000); // 2초 후 실행
printMessage(3);
// 실행 결과: 1, 3, (2초 후) 2
setInterval()지정된 시간(delay)마다 콜백 함수를 반복적으로 실행합니다.
const intervalId = setInterval(callback, delay);clearInterval(intervalId): setInterval의 반복 실행을 중지시킵니다.function printMessage(number) {
console.log(`현재 숫자: ${number}`);
}
let count = 0;
const intervalId = setInterval(() => {
printMessage(count);
count++;
if (count === 3) {
clearInterval(intervalId); // count가 3이 되면 반복 중지
console.log("타이머 중지");
}
}, 1000); // 1초마다 반복
// 실행 결과:
// 현재 숫자: 0
// (1초 후) 현재 숫자: 1
// (1초 후) 현재 숫자: 2
// (1초 후) 타이머 중지
requestAnimationFrame()브라우저의 렌더링 주기에 맞춰 콜백 함수를 실행합니다. 주로 부드러운 애니메이션을 구현할 때 사용됩니다.
const animationFrameId = requestAnimationFrame(callback);cancelAnimationFrame(animationFrameId): 콜백 함수의 실행을 취소합니다.<html>
<body>
<h1>애니메이션 타이머</h1>
<script>
let startTime;
let animationFrameId;
// 콜백 함수: timestamp는 페이지 로드 후 경과 시간입니다.
function updateTimerCallBack(timestamp) {
if (startTime === undefined) {
startTime = timestamp;
}
// 경과 시간 계산
const elapsedTime = timestamp - startTime;
console.log(`경과 시간: ${elapsedTime.toFixed(0)}ms`);
// 재귀 호출을 통해 애니메이션을 계속 실행
animationFrameId = requestAnimationFrame(updateTimerCallBack);
}
// 타이머 시작
animationFrameId = requestAnimationFrame(updateTimerCallBack);
</script>
</body>
</html>
JavaScript 엔진이 싱글 스레드임에도 불구하고 비동기 처리를 할 수 있는 이유는, JavaScript가 실행되는 환경(브라우저, Node.js)에 있습니다.
setTimeout, fetch, DOM 이벤트 등 비동기 작업을 처리하는 별도의 멀티 스레드 환경입니다.function printMessage() {
console.log("작업 완료");
}
setTimeout(printMessage, 3000); // 3초 후 실행
console.log("다른 작업 실행");
setTimeout(printMessage, 3000)이 콜 스택에 추가된 후 즉시 실행됩니다.setTimeout은 printMessage 콜백 함수와 지연 시간 3000ms를 Web API에 전달하고, 자신은 콜 스택에서 제거됩니다.console.log("다른 작업 실행")이 콜 스택에 추가되고 실행된 후 제거됩니다. "다른 작업 실행"이 콘솔에 출력됩니다.printMessage 함수를 콜백 큐로 이동시킵니다.printMessage 함수를 콜 스택으로 이동시킵니다.printMessage 함수가 실행되어 "작업 완료"가 콘솔에 출력됩니다.여러 비동기 작업을 순차적으로 처리해야 할 때, 콜백 함수가 계속해서 중첩되는 현상이 발생합니다. 이를 콜백 지옥이라고 부릅니다.
readFile("document.txt", (file) => {
// 1. 파일 읽기 완료 후 실행
console.log("파일 읽기 성공");
processFile(file, (processedFile) => {
// 2. 파일 처리 완료 후 실행
console.log("파일 처리 성공");
saveFile(processedFile, (savedFile) => {
// 3. 파일 저장 완료 후 실행
console.log("모든 작업 완료!");
});
});
});
이러한 콜백 지옥 문제를 해결하기 위해 ES6부터는 Promise와 async/await라는 더 발전된 비동기 처리 패턴이 도입되었습니다.