일정 시간이 지난 후에 원하는 함수를 예약 실행(호출)할 수 있게 하는 것을 '호출 스케줄링(scheduling a call)'이라고 합니다. 호출 스케줄링을 구현하는 방법은 두 가지가 있습니다.
자바스크립트 명세서엔 setTimeout문법:
매개변수: func|code 실행하고자 하는 코드로, 함수 또는 문자열 형태입니다. 대개는 이 자리에 함수가 들어갑니다. 하위 호환성을 위해 문자열도 받을 수 있게 해놓았지만 추천하진 않습니다.delay 실행 전 대기 시간으로, 단위는 밀리초(millisecond, 1000밀리초 = 1초)이며 기본값은 0입니다.arg1 , arg2 …함수에 전달할 인수들로, IE9 이하에선 지원하지 않습니다.예시를 통해
아래와 같이 함수에 인수를 넘겨줄 수도 있습니다.
아래 예시가 정상적으로 동작하는 이유이죠.
그런데 이렇게 문자열을 사용하는 방법은 추천하지 않습니다. 되도록 다음 예시와 같이 익명 화살표 함수를 사용하세요.
함수를 실행하지 말고 넘기세요. 초보 개발자는
clearTimeout으로 스케줄링 취소하기
스케줄링 취소하기:
아래 예시는 함수 실행을 계획해 놓았다가 중간에 마음이 바뀌어 계획해 놓았던 것을 취소한 상황을 코드로 표현하고 있습니다. 예시를 실행해도 스케줄링이 취소되었기 때문에 아무런 변화가 없는 것을 확인할 수 있습니다.
예시를 실행하면 다시 한번 말씀드리자면, 스케줄링에 관한 명세는 따로 존재하지 않습니다. 명세가 없기 때문에 호스트 환경마다 약간의 차이가 있을 수밖에 없습니다. 참고로 브라우저는 HTML5의 timers section을 준수하고 있습니다. setInterval
인수 역시 동일합니다. 다만, 함수 호출을 중단하려면 다음 예시를 실행하면 메시지가 2초 간격으로 보이다가 5초 이후에는 더 이상 메시지가 보이지 않습니다.
Chrome과 Firefox를 포함한 대부분의 브라우저는 위 예시를 실행하고 첫 번째 중첩 setTimeout무언가를 일정 간격을 두고 실행하는 방법에는 크게 2가지가 있습니다. 하나는
다섯 번째 줄의 중첩 5초 간격으로 서버에 요청을 보내 데이터를 얻는다고 가정해 봅시다. 서버가 과부하 상태라면 요청 간격을 10초, 20초, 40초 등으로 증가시켜주는 게 좋을 겁니다. 아래는 이를 구현한 의사 코드입니다.
CPU 소모가 많은 작업을 주기적으로 실행하는 경우에도 중첩 아래 두 예시를 비교해 봅시다. 첫 번째 예시에선
두 번째 예시에선 중첩
첫 번째 예시에선, 내부 스케줄러가 그림을 보고 뭔가 알아차리셨나요?
이는 그렇다면 이런 경우는 엔진이 따라서 함수 호출에 걸리는 시간이 매번 한편, 중첩 중첩
이렇게 지연 간격이 보장되는 이유는 이전 함수의 실행이 종료된 이후에 다음 함수 호출에 대한 계획이 세워지기 때문입니다. 가비지 컬렉션과 setInterval·setTimeout
그런데 이런 동작 방식에는 부작용이 하나 있습니다. 외부 렉시컬 환경을 참조하는 함수가 있다고 가정해 봅시다. 이 함수가 메모리에 남아있는 동안엔 외부 변수 역시 메모리에 남아있기 마련입니다. 그런데 이렇게 되면 실제 함수가 차지했어야 하는 공간보다 더 많은 메모리 공간이 사용됩니다. 이런 부작용을 방지하고 싶다면 스케줄링할 필요가 없어진 함수는 아무리 작더라도 취소하도록 합시다. 대기 시간이 0인 setTimeout
이렇게 대기 시간을 0으로 설정하면 이런 특징을 이용하면 현재 스크립트의 실행이 종료된 ‘직후에’ 원하는 함수가 실행될 수 있게 할 수 있습니다. 예시를 실행하면 얼럿창에 'Hello’와 'World’가 순서대로 출력되는 것을 확인할 수 있습니다.
예시에서 첫 번째 줄은 '0밀리초 후에 함수 호출하기’라는 할 일을 '계획표에 기록’해주는 역할을 합니다. 그런데 스케줄러는 현재 스크립트(alert 함수)의 실행이 종료되고 나서야 '계획표에 어떤 할 일이 적혀있는지 확인’하므로, 대기 시간이 0인 setTimeout을 활용한 브라우저 환경에서의 유스 케이스는 이벤트 루프와 매크로태스크, 마이크로태스크에서 자세히 다루도록 하겠습니다. 브라우저 환경에서 실제 대기 시간은 0이 아닙니다. 브라우저는 HTML5 표준에서 정한 중첩 타이머 실행 간격 관련 제약을 준수합니다. 해당 표준엔 "다섯 번째 중첩 타이머 이후엔 대기 시간을 최소 4밀리초 이상으로 강제해야 한다."라는 제약이 명시되어있습니다. 예시를 보며 이 제약 사항을 이해해봅시다. 예시 내
앞쪽 타이머들은 스펙에 적힌 것처럼 지연 없이 바로 실행됩니다. 그런데 다섯 번째 중첩 타이머 이후엔 지연 간격이 4밀리초 이상이 되어 이런 제약은 이는 오래전부터 있던 제약인데, 구식 스크립트 중 일부는 아직 이 제약에 의존하는 경우가 있어서 명세서를 변경하지 못하고 있는 상황입니다. 한편, 서버 측엔 이런 제약이 없습니다. Node.js의 process.nextTick과 setImmediate를 이용하면 비동기 작업을 지연 없이 실행할 수 있습니다. 위에서 언급된 제약은 브라우저에 한정됩니다. 요약
스케줄링 메서드를 사용할 땐 명시한 지연 간격이 보장되지 않을 수도 있다는 점에 유의해야 합니다. 아래와 같은 상황에서 브라우저 내 타이머가 느려지면 지연 간격이 보장되지 않습니다.
이런 상황에서 타이머의 최소 지연 시간은 300밀리초에서 심하면 1,000밀리초까지 늘어납니다. 연장 시간은 브라우저나 구동 중인 운영 체제의 성능 설정에 따라 다릅니다. |