티스토리 뷰

누군가에게 받은 질문 하나.

다음 코드는 어떤 결과가 나올까요?

 var x = true;
 
 setTimeout(() => {
   x = false;
 }, 2000);
 
 while(x) {
   console.log('hello');
 }

 

다행인지? 나는 정답을 바로 맞출 수 있었다.

 

setTimeout

 

setTimeout은 다음과 같은 형식으로 작성한다. 뜻은 5000ms 후에 "첫 번째 메시지"라는 문구를 콘솔에 띄워준다는 뜻이다.

var timeoutID = setTimeout(function[, delay]);

setTimeout(() => {console.log("첫 번째 메시지")}, 5000);

이렇듯 setTimeout은 설정한 시간이 흐른 후에 작성한 함수를 실행시켜주는 web API이다.

또한 setTimeout은 timeoutID를 반환하여주는데, 이를 이용하여 타이머를 식별할 수 있으며, clearTimeout()을 이용하여 타이머를 취소할 수 있다.

const timeId = setTimeout(() => {console.log("첫 번째 메시지")}, 5000);

clearTimeout(timeId);
참고로 setTimeout()과 setInterval()은 절대 같은 timeoutID를 반환하지 않는다.

 

setTimeout은 비동기 함수로 다음 함수 호출을 멈추게 하지 않는다.

setTimeout(() => {console.log("첫 번째 메시지")}, 5000);
setTimeout(() => {console.log("두 번째 메시지")}, 3000);
setTimeout(() => {console.log("세 번째 메시지")}, 1000);

// 콘솔 출력:

// 세 번째 메시지
// 두 번째 메시지
// 첫 번째 메시지

가령 다음과 같은 코드는 첫 번째 -> 두 번째 -> 세 번째를 호출하지만 세 번째 -> 두 번째 -> 첫 번째를 콘솔에 찍어준다. 이는 비동기의 특징으로 첫 번째 메시지를 적은 setTimeout이 먼저 실행되지만 5초 대기 시작과 동시에 두 번째 메시지인 3초, 그 다음은 세 번째 메시지인 1초를 대기한다. 5초와 3초가 아직 끝나지 않았을 때 1초가 먼저 끝나기때문에 세 번째 메시지 문구가 콘솔에 가장 먼저 찍히게 된다.

참고로 setTimeout() 함수는 이를 호출한 함수와는 다른 맥락에서 호출된다. 즉, this값이 연결되지 않는다. setTimeout()을 호출할 때, this를 지정하지 않거나 바인딩을 하지 않은 경우 this는 기본값인 window를 가리키게 된다.

 

그럼 setTimeout()을 0초 혹은 생략을 하면 어떻게 될까?

시간은 생략하거나 0으로 지정할 수 있으며, 이는 즉시 실행하라는 의미이지만 정확하게는 한 이벤트 사이클이 끝난 후 실행된다는 의미이다. 부연하여 말하자면 1초로 설정했다는 것은 이벤트 사이클이 끝난 후, 1초 뒤라는 뜻이다. 그래서 의도한 시간보다 더 오랜 시간 후에 실행될 수 있다. 

간단하게 말하면 JS는 싱글 스레드로 하나의 call stack을 가지고 있다. 함수가 호출되면 이를 콜 스택에 푸시하여 함수를 순차적으로 수행해준다. 이 때, 이벤트 루프는 콜스택을 지켜보고 있다가 콜 스택이 비면 task queue에서 실행되길 대기하고 있는 함수를 콜 스택에 푸시하여 함수가 수행되도록 해준다.

더 자세한 과정은 call stack, taskqueue(+ microTask queue), event loop를 공부하면 쉽게 이해된다.

한 이벤트 사이클은 call stack에 푸시된 함수들이 모두 수행됨을 의미한다. 다시 말하면 setTimeout은 코드가 읽혔을 때 바로 수행되는 것이 아니라 task Queue에서 대기하고 있다가 콜 스택에 있는 함수가 모두 수행되면 그 후에 call stack으로 푸시되어 특정 시간 이후 실행된다.

그래서 0초 혹은 생략이 즉시이지만 즉시가 아니고, 의도한 시간보다 더 오랜 시간이 걸릴 수 있는 것이다.

그럼 다시 상단의 코드 답은 무엇일까?

 var x = true;
 
 setTimeout(() => {
   x = false;
 }, 2000);
 
 while(x) {
   console.log('hello');
 }

바로 'hello가 무한으로 찍힌다.'가 정답이다.

x를 true로 설정한다. x를 false로 바꾸는 setTimeout()은 2초뒤에 수행되길 원하지만 사실은 taskQueue에 담기어 대기하게 된다. while은 call stack에 푸시되어 hello를 찍게 되고, 2초뒤에 실현되어야 할 setTimeout은 call stack에 있는 while문이 아직 실행되고 있기 때문에 여전히 task Queue에서 대기하게 된다. x를 false로 바꿀 수 있는 함수에 닿을 수 없기 때문에 while은 무한으로 진행된다.

 

* micro TaskQueue / Animation Frame / (macro) TaskQueue의 차이를 잘 설명한 블로그 냠냠-!

https://velog.io/@titu/JavaScript-Task-Queue%EB%A7%90%EA%B3%A0-%EB%8B%A4%EB%A5%B8-%ED%81%90%EA%B0%80-%EB%8D%94-%EC%9E%88%EB%8B%A4%EA%B3%A0-MicroTask-Queue-Animation-Frames-Render-Queue

 

[JavaScript] Task Queue말고 다른 큐가 더 있다고? (MicroTask Queue, Animation Frames)

자바스크립트에서 비동기 함수가 동작하는 원리에 대해서 공부했다면, Task Queue에 대해 들어보았을 것이다. Task Queue는 Web API가 수행한 비동기 함수를 넘겨받아 Event Loop가 해당 함수를 Call Stack에

velog.io

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함