1.1 비동기성의 기본 개념
JavaScript의 비동기성은 주요 실행 흐름을 차단하지 않고 백그라운드에서 작업을 수행할 수 있게 해줘. 이건 네트워크 요청, 파일 읽기와 같은 시간이 좀 걸릴 수 있는 작업 그리고 타이머에 특히 중요하거든. 지금 우리는 JavaScript에서 비동기 프로그래밍의 기본 개념을 살펴보고 사용 예제를 보여줄게.
JavaScript의 단일 스레드 특성
JavaScript는 단일 스레드 언어야: 이 말은 한 번에 하나의 스레드로 코드를 순차적으로 실행한다는 뜻이야. 하지만 비동기 작업은 백그라운드에서 작업을 수행하고 주요 스레드를 다른 작업을 위해 비워두게 해줘.
이벤트 루프
이벤트 루프(Event Loop)는 JavaScript가 비동기 작업을 처리할 수 있게 해주는 핵심 메커니즘이야. 이벤트 루프는 메시지 큐(Message Queue)와 마이크로태스크 큐(Microtask Queue)를 관리해서 비동기 작업 실행을 보장해줘.
- 메시지 큐: 이벤트 핸들러, 네트워크 요청과 타이머와 같은 작업을 포함해. 이 큐의 작업은 순차적으로 실행돼.
- 마이크로태스크 큐: 메시지 큐 작업보다 더 높은 우선순위를 가진 작업들이 있어. 예를 들어 Promise의 완료와 마이크로태스크에서의 콜백 호출이 포함돼.
이벤트 루프는 두 큐를 계속 확인하고 주요 스레드가 자유로워질 때 작업을 실행해.
비동기 작업
비동기 작업은 백그라운드에서 작업을 수행할 수 있게 해줘. 비동기 작업의 주요 예제는 다음과 같아:
- 타이머 (
setTimeout,setInterval) - 이벤트 핸들러
- 네트워크 요청 (예:
XMLHttpRequest,Fetch API) - 파일 읽기/쓰기 (Node.js에서)
비동기 작업의 몇 가지 예제를 보자.
1.2 타이머
타이머는 일정한 시간 후에 또는 정기적인 간격으로 작업을 수행할 수 있게 해줘.
setTimeout 사용 예제
이 예제에서는 setTimeout이 2초 후에 함수를 실행하도록 설정돼. 따라서 먼저 Start와 End가 출력되고 2초 후에 Executed after 2 seconds가 출력돼.
console.log('Start');
setTimeout(() => {
console.log('Executed after 2 seconds');
}, 2000);
console.log('End');
setInterval 사용 예제
이 예제에서는 setInterval이 매초마다 함수를 실행해, 카운터를 증가시키고 그 값을 출력해. 카운터가 5에 도달하면 clearInterval을 사용해 인터벌을 정리해:
let counter = 0;
const intervalID = setInterval(() => {
counter++;
console.log(`Counter: ${counter}`);
if (counter >= 5) {
clearInterval(intervalID);
}
}, 1000);
1.3 이벤트 핸들러
이벤트 핸들러는 사용자의 행동이나 다른 이벤트에 반응해서 코드를 실행할 수 있게 해줘.
이벤트 핸들러 사용 예제
이 예제에서는 click 이벤트 핸들러가 버튼에 추가돼. 사용자가 버튼을 클릭하면 Button clicked!라는 메시지가 출력돼:
<!DOCTYPE html>
<html>
<head>
<title>Event Handler Example</title>
</head>
<body>
<button id="myButton">Click me</button>
<script>
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked!');
});
</script>
</body>
</html>
1.4 네트워크 요청
네트워크 요청은 서버로 비동기 HTTP 요청을 수행할 수 있게 해줘.
XMLHttpRequest 사용 예제
이 예제에서는 API에 비동기 GET 요청을 보내고, 요청이 완료되면 응답을 콘솔에 출력해:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
console.log(response);
}
};
xhr.send();
1.5 이벤트 루프 동작
이벤트 루프가 어떻게 동작하는지 더 잘 이해하기 위해 다음 예제를 봐보자:
console.log('Start');
setTimeout(() => {
console.log('Timeout 1');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 1');
});
setTimeout(() => {
console.log('Timeout 2');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 2');
});
console.log('End');
기대되는 출력은 다음과 같아:
StartEndPromise 1Promise 2Timeout 1Timeout 2
이 예제에서는 먼저 동기 작업(console.log('Start')와 console.log('End'))이 실행돼. 그 다음에 마이크로태스크 (Promise 핸들러)가 실행되고, 그 후에야 메시지 큐의 작업(setTimeout)이 실행돼.
GO TO FULL VERSION