λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

πŸ‘©πŸ»‍πŸ’»STUDY/JavaScript

[JavaScript] μŠ€μΌ€μ€„λ§ setTimeout κ³Ό setInterval

λ°˜μ‘ν˜•

[JavaScript] setTimeoutκ³Ό setInterval

좜처 :: μŠ€μΌ€μ€„λ§: setTimeoutκ³Ό setInterval

 

일정 μ‹œκ°„μ΄ μ§€λ‚œ 후에 μ›ν•˜λŠ” ν•¨μˆ˜λ₯Ό μ˜ˆμ•½ μ‹€ν–‰(호좜)ν•  수 있게 ν•˜λŠ” 것을 "호좜 μŠ€μΌ€μ€„λ§(scheduling a call)"이라 ν•œλ‹€. 호좜 μŠ€μΌ€μ€„λ§μ„ κ΅¬ν˜„ν•˜λŠ” 방법은 두 가지가 μžˆλ‹€.

  • setTimeout :: 일정 μ‹œκ°„μ΄ μ§€λ‚œ 후에 ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•˜λŠ” 방법.

  • setInterval :: 일정 μ‹œκ°„ 간격을 두고 ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•˜λŠ” 방법.

    μžλ°”μŠ€ν¬λ¦½νŠΈ λͺ…μ„Έμ„œμ—” setTimeoutκ³Ό setIntervalκ°€ λͺ…μ‹œλ˜μ–΄ μžˆμ§€ μ•Šλ‹€. ν•˜μ§€λ§Œ μ‹œμ€‘μ— λ‚˜μ™€μžˆλŠ” λͺ¨λ“  λΈŒλΌμš°μ €, Node.jsλ₯Ό ν¬ν•¨ν•œ μžλ°”μŠ€ν¬λ¦½νŠΈ 호슀트 ν™˜κ²½ λŒ€λΆ€λΆ„ 이와 μœ μ‚¬ν•œ λ©”μ„œλ“œμ™€ λ‚΄λΆ€ μŠ€μΌ€μ€„λŸ¬λ₯Ό μ§€μ›ν•œλ‹€.

 

setTimeout

문법 ::

let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...)

λ§€κ°œλ³€μˆ˜ ::

func|code

μ‹€ν–‰ν•˜κ³ μž ν•˜λŠ” μ½”λ“œ. ν•¨μˆ˜ λ˜λŠ” λ¬Έμžμ—΄ ν˜•νƒœμ΄λ‹€. λŒ€κ°œλŠ” 이 μžλ¦¬μ— ν•¨μˆ˜κ°€ λ“€μ–΄κ°„λ‹€. ν•˜μœ„ ν˜Έν™˜μ„±μ„ μœ„ν•΄ λ¬Έμžμ—΄λ„ 받을 수 있게 ν•΄λ†“μ•˜μœΌλ‚˜, μΆ”μ²œν•˜μ§€λŠ” μ•ŠλŠ”λ‹€.

delay

μ‹€ν–‰ μ „ λŒ€κΈ° μ‹œκ°„(지연 간격)으둜, λ‹¨μœ„λŠ” λ°€λ¦¬μ΄ˆ(millisecond, 100λ°€λ¦¬μ΄ˆ = 1초)이닀. 기본값은 0.

arg1, arg2...

ν•¨μˆ˜μ— 전달할 μΈμˆ˜λ“€λ‘œ, IE9 μ΄ν•˜μ—μ„  μ§€μ›ν•˜μ§€ μ•ŠλŠ”λ‹€.

 

예제 ::

μ•„λž˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λ©΄ 1초 ν›„ sayHi()κ°€ ν˜ΈμΆœλœλ‹€.

function sayHi() {
  alert('Hello');
}
setTimeout(sayHi, 1000);

μ•„λž˜μ™€ 같이 ν•¨μˆ˜μ— 인수λ₯Ό λ„˜κ²¨ 쀄 수 μžˆλ‹€.

function sayHi(phrase, who) {
  alert(phrase + ', ' + who);
}
setTimeout(sayHi, 1000, 'Hello', 'John'); // Hello, John

setTimeout의 첫 번째 μΈμˆ˜κ°€ λ¬Έμžμ—΄μ΄λ©΄, μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” 이 λ¬Έμžμ—΄μ„ μ΄μš©ν•΄ ν•¨μˆ˜λ₯Ό λ§Œλ“ λ‹€.

setTImeout('alert("Hello")', 1000);

ν•˜μ§€λ§Œ λ¬Έμžμ—΄ μ‚¬μš© 방법은 μΆ”μ²œν•˜μ§€ μ•ŠλŠ”λ‹€. μ•„λž˜μ™€ 같이 μ‚¬μš©ν•˜μž.

setTimeout(function() { alert('Hello') }, 1000);
// λ˜λŠ” ν™”μ‚΄ν‘œν•¨μˆ˜
setTimeout(() => alert('Hello'), 1000);

 

β—οΈν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•˜μ§€ 말고 λ„˜κΈ°μž.

μ΄ˆλ³΄κ°œλ°œμžλŠ” setTimeout에 ν•¨μˆ˜λ₯Ό λ„˜κΈΈ λ•Œ, ν•¨μˆ˜ 뒀에 ()을 λΆ™μ΄λŠ” μ‹€μˆ˜λ₯Ό ν•œλ‹€.

// 잘λͺ»λœ μ½”λ“œ
setTimeout(sayHi(), 1000);

setTimeout은 ν•¨μˆ˜μ˜ 참쑰값을 λ°›λŠ”λ‹€. 그런데 sayHi()λ₯Ό 인수둜 μ „λ‹¬ν•˜λ©΄ ν•¨μˆ˜ μ‹€ν–‰ κ²°κ³Όκ°€ μ „λ‹¬λ˜μ–΄ 버린닀. sayHi()μ—λŠ” λ°˜ν™˜λ¬Έμ΄ μ—†κΈ° λ•Œλ¬Έμ— μ‹€ν–‰ κ²°κ³ΌλŠ” undefined으둜 λ‚˜μ˜¨λ‹€. setTimeout은 μŠ€μΌ€μ€„λ§ν•  λŒ€μƒμ„ 찾지 λͺ»ν•΄, μ›ν•˜λŠ” λŒ€λ‘œ μ½”λ“œκ°€ λ™μž‘ν•˜μ§€ μ•ŠλŠ”λ‹€.

 

clearTimeout으둜 μŠ€μΌ€μ€„λ§ μ·¨μ†Œν•˜κΈ°

setTimeout을 ν˜ΈμΆœν•˜λ©΄ "타이머 μ‹λ³„μž(timer identifier)"κ°€ λ°˜ν™˜λœλ‹€. μŠ€μΌ€μ€„λ§μ„ μ·¨μ†Œν•˜κ³  싢을 땐 μ‹λ³„μž(μ•„λž˜ μ˜ˆμ‹œμ—μ„œ timerId)λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.

let timerId = setTImeout(() => alert('μ•„λ¬΄λŸ° 일도 μΌμ–΄λ‚˜μ§€ μ•ŠλŠ”λ‹€.'), 1000);
alert(timerId); // 타이머 μ‹λ³„μž

clearTimeout(timerId);
alert(timerId); // μœ„ 타이머 μ‹λ³„μžμ™€ 동일함.(μ·¨μ†Œ 후에도 μ‹λ³„μžμ˜ 값은 null이 λ˜μ§€ μ•ŠλŠ”λ‹€.)

μ˜ˆμ‹œλ₯Ό μ‹€ν–‰ν•˜λ©΄ alert 창이 2개 λœ¨λŠ”λ°, λΈŒλΌμš°μ € ν™˜κ²½μ—μ„  타이머 μ‹λ³„μžκ°€ μˆ«μžλΌλŠ” 것을 μ•Œ 수 μžˆλ‹€.

λ‹€λ₯Έ 호슀트 ν™˜κ²½μ—μ„  타이머 μ‹λ³„μžκ°€ μˆ«μžν˜• μ΄μ™Έμ˜ μžλ£Œν˜•μΌ μˆ˜λ„ μžˆλ‹€. Node.jsμ—μ„œλŠ” setTimeout을 μ‹€ν–‰ν•˜λ©΄ 타이머 객체가 λ°˜ν™˜λœλ‹€.

μŠ€μΌ€μ€„λ§μ— κ΄€ν•œ λͺ…μ„ΈλŠ” λ”°λ‘œ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€. λͺ…μ„Έκ°€ μ—†κΈ° λ•Œλ¬Έμ— 호슀트 ν™˜κ²½λ§ˆλ‹€ μ•½κ°„μ˜ 차이가 μžˆμ„ 수 밖에 μ—†λ‹€.

참고둜 λΈŒλΌμš°μ €λŠ” HTML5의 timers section을 μ€€μˆ˜ν•˜κ³  μžˆλ‹€.

 

setInterval

setInterval λ©”μ„œλ“œλŠ” setTimeoutκ³Ό λ™μΌν•œ 문법을 μ‚¬μš©ν•œλ‹€.

let timerId = setInterval(func|code, [delay], [arg1], [arg2], ...)

인수 μ—­μ‹œ λ™μΌν•˜λ‚˜, setTimeout이 ν•¨μˆ˜λ₯Ό 단 ν•œλ²ˆλ§Œ μ‹€ν–‰ν•˜λŠ” 것과 달리, setInterval은 ν•¨μˆ˜λ₯Ό 주기적으둜 μ‹€ν–‰ν•œλ‹€.

ν•¨μˆ˜ ν˜ΈμΆœμ„ μ€‘λ‹¨ν•˜λ €λ©΄ clearInterval(timerId)을 μ‚¬μš©ν•œλ‹€.

 

μ•„λž˜ 예제λ₯Ό μ‹€ν–‰ν•˜λ©΄ 메세지가 2초 κ°„κ²©μœΌλ‘œ 보여지닀가 5초 μ΄ν›„μ—λŠ” 더 이상 메세지가 보이지 μ•ŠλŠ”λ‹€.

// 2초 κ°„κ²©μœΌλ‘œ 메세지λ₯Ό λ³΄μ—¬μ€Œ
let timerId = setInterval(() => alert('tick'), 2000);

// 5초 후에 정지
setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000);

 

❗️alert창이 λ–  μžˆλ”λΌλ„ νƒ€μ΄λ¨ΈλŠ” λ©ˆμΆ”μ§€ μ•ŠλŠ”λ‹€.

크둬과 νŒŒμ΄μ–΄ν­μŠ€λ₯Ό ν¬ν•¨ν•œ λŒ€λΆ€λΆ„μ˜ λΈŒλΌμš°μ €λŠ” alert / confirm / prompt창이 λ–  μžˆλŠ” λ™μ•ˆμ—λ„ λ‚΄λΆ€ 타이머λ₯Ό λ©ˆμΆ”μ§€ μ•ŠλŠ”λ‹€.

μœ„ μ˜ˆμ œλ“€μ„ μ‹€ν–‰ν•˜κ³  첫 번째 alert창이 떴을 λ•Œ λͺ‡ μ΄ˆκ°„ κΈ°λ‹€λ Έλ‹€κ°€ 창을 λ‹«μœΌλ©΄, 두 번째 alert창이 λ°”λ‘œ λ‚˜νƒ€λ‚˜λŠ” 것을 보고 이λ₯Ό 확인 ν•  수 μžˆλ‹€. λͺ…μ‹œν•œ 지연 μ‹œκ°„ 2μ΄ˆλ³΄λ‹€ alertμ°½ 간격이 짧아진닀.

 

 

쀑첩 setTimeout

무언가λ₯Ό 일정 간격을 두고 μ‹€ν–‰ν•˜λŠ” 방법은 크게 2가지가 μžˆλ‹€.

ν•˜λ‚˜λŠ” setInterval을 μ΄μš©ν•˜λŠ” 방법이고, λ‹€λ₯Έ ν•˜λ‚˜λŠ” μ•„λž˜ μ˜ˆμ‹œμ™€ 같이 쀑첩 setTimeout을 μ΄μš©ν•˜λŠ” 방법이닀.

/* setInterval을 μ΄μš©ν•˜μ§€ μ•Šκ³  μ•„λž˜μ™€ 같이 쀑첩 setTimeout을 μ‚¬μš©ν•¨ */

// let timerId = setInterval(() => alert('tick'), 2000);

let timerId = setTimeout(function tick() {
  alert('tick');
  timerId = setTimeout(tick, 2000); // (*)
}, 2000);
// 2μ΄ˆλ§ˆλ‹€ λ°œμƒ

setTimeout은 (*)둜 ν‘œμ‹œν•œ μ€„μ˜ 싀행이 μ’…λ£Œλ˜λ©΄ λ‹€μŒ ν˜ΈμΆœμ„ μŠ€μΌ€μ€„λ§ν•œλ‹€.

쀑첩 setTimeout을 μ΄μš©ν•˜λŠ” 방법은 setInterval을 μ‚¬μš©ν•˜λŠ” 방법보닀 μœ μ—°ν•˜λ‹€. 호좜 결과에 따라 ν˜ΈμΆœμ„ μ›ν•˜λŠ” λ°©μ‹μœΌλ‘œ μ‘°μ •ν•΄ μŠ€μΌ€μ€„λ§ ν•  수 있기 λ•Œλ¬Έμ΄λ‹€.

 

5μ΄ˆκ°„κ²©μœΌλ‘œ μ„œλ²„μ— μš”μ²­μ„ 보내 데이터λ₯Ό μ–»κ³  μžˆλ‹€κ³  κ°€μ •ν•΄λ³΄μž. μ„œλ²„κ°€ κ³ΌλΆ€ν•˜μƒνƒœλΌλ©΄ μš”μ²­ 간격을 10초, 20초, 40초 λ“±μœΌλ‘œ μ¦κ°€μ‹œμΌœμ£ΌλŠ” 것이 쒋을 것이닀. μ•„λž˜λŠ” 이λ₯Ό κ΅¬ν˜„ν•œ μ˜μ‚¬ μ½”λ“œμ΄λ‹€.

let delay = 5000;

let timerId = setTimeout(function request() {
  // .. μš”μ²­ 보내기 ..
  if(/* μ„œλ²„ κ³ΌλΆ€ν•˜λ‘œ μΈν•œ μš”μ²­ μ‹€νŒ¨ */) {
     // μš”μ²­ 간격을 λŠ˜λ¦°λ‹€.
     delay *= 2;
     }
  timerId = setTimeout(request, delay);
}, delay);

 

CPU μ†Œλͺ¨κ°€ λ§Žμ€ μž‘μ—…μ„ 주기적으둜 μ‹€ν–‰ν•˜λŠ” κ²½μš°μ—λ„ setTimeout을 μž¬κ·€ μ‹€ν–‰ν•˜λŠ” 방법이 μœ μš©ν•˜λ‹€. μž‘μ—…μ— κ±Έλ¦¬λŠ” μ‹œκ°„μ— 따라 λ‹€μŒ μž‘μ—…μ„ μœ λ™μ μœΌλ‘œ κ³„νšν•  수 있기 λ•Œλ¬Έμ΄λ‹€.

쀑첩 setTimeout을 μ΄μš©ν•˜λŠ” 방법은 지연간격을 보μž₯ν•˜λ‚˜, setInterval은 이λ₯Ό 보μž₯ν•˜μ§€ μ•ŠλŠ”λ‹€.

 

μ•„λž˜ 두 μ˜ˆμ‹œλ₯Ό λΉ„κ΅ν•΄λ³΄μž. μ²«λ²ˆμ§ΈλŠ” setInterval을 μ΄μš©ν•˜μ˜€λ‹€.

let i = 1;
setInterval(function() {
  func(i++);
}, 100);

두 번째 μ˜ˆμ‹œμ—μ„  쀑첩setTimeout을 μ΄μš©ν–ˆλ‹€.

let i = 1;
setTimeout(function run() {
  func(i++);
  setTimeout(run, 100);
}, 100);

setInerval을 μ΄μš©ν•œ μ˜ˆμ‹œμ—μ„ , λ‚΄λΆ€ μŠ€μΌ€μ€„λŸ¬κ°€ func(i++)λ₯Ό 100λ°€λ¦¬μ΄ˆλ§ˆλ‹€ μ‹€ν–‰ν•œλ‹€.

 

setInterval

setInterval을 μ‚¬μš©ν•˜λ©΄ func 호좜 μ‚¬μ΄μ˜ 지연 간격이 μ‹€μ œ λͺ…μ‹œν•œ 간격(100ms)보닀 짧아진닀.

func을 μ‹€ν–‰ν•˜λŠ”λ° "μ†Œλͺ¨λ˜λŠ”" μ‹œκ°„μ΄ 지연 간격에 ν¬ν•¨λ˜κΈ° λ•Œλ¬Έμ— 이런 일이 λ°œμƒν•œλ‹€. μ§€κ·Ήνžˆ 정상적인 λ™μž‘μ΄λΌ ν•  수 μžˆλ‹€.

그런데 func을 μ‹€ν–‰ν•˜λŠ”λ° κ±Έλ¦¬λŠ” μ‹œκ°„μ΄ λͺ…μ‹œμ  지연 간격보닀 κΈΈλ©΄ μ–΄λ–»κ²Œ 될까?

이런 경우 엔진이 func의 싀행이 μ’…λ£Œλ  λ•ŒκΉŒμ§€ κΈ°λ‹€λ €μ€€λ‹€. func의 싀행이 μ’…λ£Œλ˜λ©΄ 엔진은 μŠ€μΌ€μ€„λŸ¬λ₯Ό ν™•μΈν•˜κ³ , μ΄λ•Œ 지연 μ‹œκ°„μ΄ μ§€λ‚¬μœΌλ©΄ λ‹€μŒ ν˜ΈμΆœμ„ λ°”λ‘œ μ‹œμž‘ν•œλ‹€.

ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  λ•Œλ§ˆλ‹€ κ±Έλ¦¬λŠ” μ‹œκ°„μ΄ delay λ°€λ¦¬μ΄ˆλ³΄λ‹€ κΈΈλ©΄, λͺ¨λ“  ν•¨μˆ˜κ°€ μ‰Ό 없이 계속 연속 ν˜ΈμΆœλœλ‹€.

 

이에 λ°˜ν•΄ 쀑첩, setTimeout을 μ΄μš©ν•˜λ©΄ μ•„λž˜μ™€ 같이 싀행흐름이 이어진닀.

 


쀑첩 setTimeout

 

쀑첩 setTimeout을 μ‚¬μš©ν•˜λ©΄ λͺ…μ‹œν•œ 지연(μ—¬κΈ°μ„œλŠ” 100ms)이 보μž₯λœλ‹€.

μ΄λ ‡κ²Œ 지연 간격이 보μž₯λ˜λŠ” μ΄μœ λŠ” 이전 ν•¨μˆ˜μ˜ 싀행이 μ’…λ£Œλœ 이후에 λ‹€μŒ ν•¨μˆ˜ ν˜ΈμΆœμ— λŒ€ν•œ κ³„νšμ΄ μ„Έμ›Œμ§€κΈ° λ•Œλ¬Έμ΄λ‹€.

❗️가비지 μ»¬λ ‰μ…˜κ³Ό setInterval / setTimeout

setIntervalμ΄λ‚˜ setTimeout에 ν•¨μˆ˜λ₯Ό λ„˜κΈΈ λ•Œ, ν•¨μˆ˜μ— λŒ€ν•œ λ‚΄λΆ€ μ°Έμ‘°κ°€ μƒˆλ‘­κ²Œ λ§Œλ“€μ–΄μ§€κ³  μ°Έμ‘° 정보가 μŠ€μΌ€μ€„λŸ¬μ— μ €μž₯λœλ‹€. λ”°λΌμ„œ ν•΄λ‹Ή ν•¨μˆ˜λ₯Ό μ°Έμ‘°ν•˜λŠ” 것이 없어도 setInterval / setTimeout에 λ„˜κΈ΄ ν•¨μˆ˜λŠ” 가비지 μ»¬λ ‰μ…˜μ˜ λŒ€μƒμ΄ λ˜μ§€ μ•ŠλŠ”λ‹€.

// μŠ€μΌ€μ€„λŸ¬κ°€ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  λ•ŒκΉŒμ§€ ν•¨μˆ˜λŠ” λ©”λͺ¨λ¦¬μ— μœ μ§€λœλ‹€.
setTimeout(function() {...}, 100);

setInterval에 λ„˜κ²¨μ£ΌλŠ” ν•¨μˆ˜λŠ” clearInterval이 호좜되기 μ „κΉŒμ§€ λ©”λͺ¨λ¦¬μ— μœ μ§€λœλ‹€.

그런데 이런 λ™μž‘ λ°©μ‹μ—λŠ” λΆ€μž‘μš©μ΄ ν•˜λ‚˜ μžˆλ‹€. ν•¨μˆ˜κ°€ μ™ΈλΆ€ λ ‰μ‹œμ»¬ ν™˜κ²½μ„ μ°Έμ‘°ν•˜κ³  있으면 ν•΄λ‹Ή ν•¨μˆ˜κ°€ λ©”λͺ¨λ¦¬μ— λ‚¨μ•„μžˆλŠ” λ™μ•ˆ, μ™ΈλΆ€ λ³€μˆ˜ μ—­μ‹œ λ©”λͺ¨λ¦¬μ— λ‚¨μ•„μžˆκΈ° λ•Œλ¬Έμ΄λ‹€. μ΄λ ‡κ²Œ 되면 μ‹€μ œ ν•¨μˆ˜κ°€ μ°¨μ§€ν–ˆμ–΄μ•Ό ν•˜λŠ” 곡간보닀 더 λ§Žμ€ λ©”λͺ¨λ¦¬ 곡간이 μ‚¬μš©λœλ‹€. 이런 λΆ€μž‘μš©μ„ λ°©μ§€ν•˜λ €λ©΄ μŠ€μΌ€μ€„λ§ν•  ν•„μš”κ°€ 없어진 ν•¨μˆ˜λŠ” 아무리 μž‘λ”λΌλ„ μ·¨μ†Œν•΄μ•Ό ν•œλ‹€.

 

μΆ”κ°€ λ‚΄μš©

μžλ°”μŠ€ν¬λ¦½νŠΈ 타이밍 이벀트

1. delay에 λŒ€ν•˜μ—¬

μ–Έλœ» λ³΄κΈ°μ—λŠ” setIntervalκ³Ό setTimeoutν•¨μˆ˜λŠ” 맀우 μœ μ‚¬ν•œ 점이 λ§Žλ‹€. λ‹€λ₯Έμ μ΄λΌ ν•˜λ©΄ λ°˜λ³΅μ‹€ν–‰μ„ ν•˜λŠλƒ, ν•œ 번 μ‹€ν–‰ν•˜λŠλƒμ— μ •λ„λ‘œ 보일 μˆ˜λ„ μžˆλ‹€ ν•˜μ§€λ§Œ 정말 λ‹€λ₯Έ 점은 μ§€μ—°μ‹œκ°„(Delay)κ³Ό 각 ν•¨μˆ˜μ˜ 처리 방식이닀.

1.1) setInterval

Real delay for setInterval is actually less than given. If the execution is impossible, it is queued. If the browser is busy, and the execution is already queued, setInterval skips it.

[좜처] Javascript Tutorial - Understanding timers: setTimeout and setInterval

μ„€λͺ…ν•˜μžλ©΄ setIntervalν•¨μˆ˜μ˜ μ‹€μ œ μ§€μ—°μ‹œκ°„μ€ κ°œλ°œμžκ°€ μ€€ μ‹œκ°„λ³΄λ‹€ μ‹€μ œμ μœΌλ‘œ μ λ‹€λŠ” λœ»μ΄λ‹€. λ˜ν•œ μ‹€ν–‰ν•  수 μ—†λŠ” μƒνƒœλΌλ©΄ 큐에 μ €μž₯λœλ‹€. λ˜ν•œ λ§Œμ•½μ— λΈŒλΌμš°μ €κ°€ μ²˜λ¦¬ν•  수 μ—†λŠ” μƒνƒœ(λ°”μœ μƒνƒœ)이고, 이미 큐에 μ €μž₯된 것이 μžˆλ‹€λ©΄ setInterval은 λ¬΄μ‹œν•œλ‹€.

λ‹€μ‹œ λ§ν•΄μ„œ setInterval은 μ§€μ •λœ μ‹œκ°„ κ°„κ²©λ§ŒνΌ 무쑰건 μ§€μ •λœ μ½”λ“œλ₯Ό ν˜ΈμΆœν•˜κ³ μž ν•œλ‹€. ν•˜μ§€λ§Œ μ§€μ •λœ μ‹œκ°„ 간격에 λ„λ‹¬ν–ˆμŒμ—λ„ λΆˆκ΅¬ν•˜κ³  μ§€μ •λœ μ½”λ“œλ₯Ό μ‹€ν–‰ν•  수 μ—†λŠ” μƒνƒœλΌλ©΄ setInterval은 이벀트λ₯Ό 큐(queue)에 μ €μž₯ν•œλ‹€.

μ—¬κΈ°μ„œ 큐(queue)λ₯Ό 쑰금 더 μžμ„Ένžˆ μ•Œμ•„λ³΄μž. setIntervalμ—μ„œ 큐의 ν¬κΈ°λŠ” 1이닀. ν•˜λ‚˜μ˜ μ‹€ν–‰λ§Œμ„ μ €μž₯ν•  수 μžˆλ‹€. 그리고 큐에 μ €μž₯된 것이 μžˆλ‹€λ©΄ μ‹€ν–‰ν•΄μ•Όν•  μ‹œκ°„ κ°„κ²©κ³ΌλŠ” 관계 없이 μ‹€ν–‰ κ°€λŠ₯ν•œ μƒνƒœμΌ λ•Œ, μ¦‰μ‹œ νμ—μ„œ 이벀트λ₯Ό κΊΌλ‚΄ μ‹€ν–‰ν•˜κ²Œ λ˜μ–΄ μžˆλ‹€.

ν•˜μ§€λ§Œ 쑰금 더 κΌ¬μ•„μ„œ μƒκ°ν•΄λ³΄μž. 정해진 μ‹œκ°„μ€ 100ms라고 κ°€μ •. 그러면 setInterval이 처음 μ‹€ν–‰ν•  λ•ŒλŠ” 100msμ‹œκ°„λŒ€μ—μ„œ μ§€μ •λœ μ½”λ“œ(A)λ₯Ό μ‹€ν–‰ν•  것이닀. 그리고 200msλΌλŠ” μ‹œκ°„λŒ€κ°€ 되면 λ‹€μ‹œ ν•œλ²ˆ μ§€μ •λœ μ½”λ“œ(B)λ₯Ό μ‹€ν–‰ν•˜λ € ν•  것이닀. ν•˜μ§€λ§Œ 이전 μ½”λ“œ(A) 지연 λ“±μ˜ 이유둜 μ‹€ν–‰ν•  수 μ—†λŠ” μƒνƒœλΌλ©΄ setInterval은 ν˜„μž¬ μ‹€ν–‰ν•  μ½”λ“œ(B)λ₯Ό 큐에 μ €μž₯ν•œλ‹€. 그리고 300msλΌλŠ” μ‹œκ°„λŒ€κ°€ λ˜μ–΄ λ‹€μ‹œ μ§€μ •λœ μ½”λ“œ(C)λ₯Ό μ‹€ν–‰ν•˜λ € ν•œλ‹€. ν•˜μ§€λ§Œ μ΄μ „μ½”λ“œ(Aκ°€ 아직 λλ‚˜μ§€ μ•Šμ€ μƒνƒœμ—μ„œ 큐에 이미 μ‹€ν–‰ν•  μ½”λ“œ(B)κ°€ μ €μ •λ˜μ–΄ μžˆλ‹€λ©΄ setInterval은 ν˜„μž¬ μ‹€ν–‰ν•  μ½”λ“œ(C)λ₯Ό λ¬΄μ‹œν•œλ‹€.

setInterval은 정해진 μ‹œκ°„ κ°„κ²©λ‚΄μ—μ„œ μ§€μ •λœ μ½”λ“œκ°€ μ‹€ν–‰λ˜λŠ” 경우 κΉ”λ”ν•˜κ²Œ μ²˜λ¦¬ν•  수 μžˆλŠ” ν•¨μˆ˜μ΄λ‹€.

ν•˜μ§€λ§Œ μ§€μ •λœ μ½”λ“œκ°€ μ§€μ—°λ˜μ–΄ λ‹€μŒ 이벀트 λ°œμƒμ‹œν‚€κΈ°κΉŒμ§€ 영ν–₯을 λΌμΉ˜λŠ” 경우 "λ¬΄μ‹œ λ‹Ήν•˜λŠ” 이벀트"κ°€ 생길 μ—Όλ €κ°€ μžˆλ‹€.

 

1.2) setTimeout

setTimeoutν•¨μˆ˜λŠ” 단 ν•œλ²ˆ μ§€μ •λœ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜μ§€λ§Œ μž¬κ·€ν˜ΈμΆœ λ“±μ˜ 방법을 μ΄μš©ν•΄μ„œ 반볡적으둜 ν˜ΈμΆœν•  수 μžˆλ‹€.

setTimeoutν•¨μˆ˜λŠ” μ§€μ •λœ μ‹œκ°„λ§ŒνΌμ„ κΈ°λ‹€λ¦° ν›„ μ§€μ •λœ μ½”λ“œλ₯Ό μ‹€ν–‰ν•œλ‹€. 그리고 λ‹€μŒ ν˜ΈμΆœν•˜λŠ” μ‹œκΈ°λŠ” μ§€μ •λœ μ½”λ“œ λ‚΄μ—μ„œ μ •μ˜κ°€ κ°€λŠ₯ν•˜λ‹€.

function foo() {
  // process..
  loop = setTimeout(function() { foo() }, 1000);
}
var loop = setTimeout(function() { foo() }, 1000);

μœ„ μ½”λ“œλŠ” μ§€μ •λœ μ½”λ“œ(processμ£Όμ„μ²˜λ¦¬λœ 것) 이후에 λ‹€μ‹œ setTimeout으둜 μž¬κ·€ν˜ΈμΆœμ„ ν•˜κ³  μžˆλ‹€. μ΄λ ‡κ²Œ 처리λ₯Ό ν•œλ‹€λ©΄ setIntervalμ—μ„œ 봀던 μ΄λ²€νŠΈκ°€ λ¬΄μ‹œλ‹Ήν•  일은 μ—†λ‹€.

예λ₯Ό λ“€μ–΄, setTimeout을 μ‹€ν–‰ν•˜λ©΄ 처음 μ§€μ •λœ κ°„κ²©λ§ŒνΌ κΈ°λ‹€λ¦° ν›„ μ§€μ •λœ μ½”λ“œλ₯Ό μ‹€ν–‰ν•œλ‹€. 그리고 μ§€μ •λœ μ½”λ“œκ°€ λλ‚œ μ‹œμ μ—μ„œ λ‹€μ‹œ setTimeoutν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œλ‹€. 그러면 μ§€μ •λœ μ½”λ“œκ°€ μ§€μ—°λ˜λ”λΌλ„ λͺ¨λ“  μ²˜λ¦¬κ°€ λλ‚œ λ‹€μŒ setTimeout을 ν˜ΈμΆœν•˜κΈ° λ•Œλ¬Έμ— μ΄λ²€νŠΈκ°€ 쀑첩될 일은 없을 것이닀. (ajax λ“±μ˜ 비동기적 μ½”λ“œκ°€ μžˆλ‹€λ©΄ μ½œλ°±ν•¨μˆ˜μ²˜λŸΌ λ§Œλ“€μ–΄μ•Ό ν•  ν•„μš”λŠ” μžˆλ‹€.)

 


 

λŒ€κΈ°μ‹œκ°„μ΄ 0인 setTimeout

setTimeout(func, 0)μ΄λ‚˜ setTimeout(func)을 μ‚¬μš©ν•˜λ©΄ setTimeout의 λŒ€κΈ°μ‚¬κ°„μ„ 0으둜 μ„€μ • ν•  수 μžˆλ‹€. μ΄λ ‡κ²Œ λŒ€κΈ° μ‹œκ°„μ„ 0으둜 μ„€μ •ν•˜λ©΄ func을 κ°€λŠ₯ν•œ 빨리 μ‹€ν–‰ν•  수 μžˆλ‹€. λ‹€λ§Œ, μ΄λ•Œ μŠ€μΌ€μ€„λŸ¬λŠ” ν˜„μž¬ 싀행쀑인 슀크립트의 μ²˜λ¦¬κ°€ μ’…λ£Œλœ 이후에 μŠ€μΌ€μ€„λ§ν•œ ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œλ‹€.

이런 νŠΉμ§•μ„ μ΄μš©ν•˜λ©΄ ν˜„μž¬ 슀크립트의 싀행이 μ’…λ£Œλœ "직후에" μ›ν•˜λŠ” ν•¨μˆ˜λ₯Ό 싀행될 수 있게 ν•΄μ€€λ‹€.

μ•„λž˜ μ˜ˆμ‹œλ₯Ό μ‹€ν–‰ν•˜λ©΄ μ–ΌλŸΏμ°½μ— "Hello"와 "World"κ°€ μ΄μ–΄μ„œ 좜λ ₯λœλ‹€.

setTimeout(() => alert('World'));
alert('Hello');

μœ„ μ˜ˆμ‹œμ—μ„œ 첫 번째 쀄은 "'0λ°€λ¦¬μ΄ˆ 후에 ν•¨μˆ˜ ν˜ΈμΆœν•˜κΈ°'λΌλŠ” ν•  일을 κ³„νšν‘œμ— 기둝"ν•΄μ£ΌλŠ” 역할을 ν•œλ‹€. 그런데 μŠ€μΌ€μ€„λŸ¬λŠ” ν˜„μž¬ 슀크립트(alertν•¨μˆ˜)의 싀행이 μ’…λ£Œλ˜κ³  λ‚˜μ„œμ•Ό "κ³„νšν‘œμ— μ–΄λ–€ ν•  일이 μ ν˜€ μžˆλŠ”μ§€ 확인"ν•˜λ―€λ‘œ, "Hello"κ°€ λ¨Όμ €, "World"은 κ·Έ λ‹€μŒ 좜λ ₯λœλ‹€.

λŒ€κΈ°μ‹œκ°„μ΄ 0인 setTimeout을 ν™œμš©ν•œ λΈŒλΌμš°μ € ν™˜κ²½μ—μ„œμ˜ μ‚¬λ‘€λŠ” Event loop: microtasks and macrotasksμ—μ„œ μžμ„Ένžˆ 닀룬닀.

 

β—οΈλΈŒλΌμš°μ € ν™˜κ²½μ—μ„œ μ‹€μ œ λŒ€κΈ° μ‹œκ°„μ€ 0이 μ•„λ‹ˆλ‹€.

λΈŒλΌμš°μ €λŠ” HTML5ν‘œμ€€μ—μ„œ μ •ν•œ 쀑첩 타이머 μ‹€ν–‰ 간견 κ΄€λ ¨ μ œμ•½μ‚¬ν•­μ„ μ€€μˆ˜ν•œλ‹€. ν•΄λ‹Ή ν‘œμ€€μ—” "λ‹€μ„― 번째 쀑첩 타이머 이후엔 λŒ€κΈ° μ‹œκ°„μ„ μ΅œμ†Œ 4λ°€λ¦¬μ΄ˆ 이상을 κ°•μ œν•΄μ•Ό ν•œλ‹€."λΌλŠ” 사항이 λͺ…μ‹œλ˜μ–΄ μžˆλ‹€.

μ˜ˆμ‹œλ₯Ό 톡해 이 μ œμ•½μ‚¬ν•­μ„ μ΄ν•΄ν•΄λ³΄μž. μ˜ˆμ‹œμ— 쓰인 setTimeout은 지연없이 ν•¨μˆ˜ run을 λ‹€μ‹œ ν˜ΈμΆœν•  수 있게 μŠ€μΌ€μ€„λ§ λ˜μ–΄μžˆλ‹€. λ°°μ—΄timesμ—λŠ” μ‹€μ œ 지연 간격에 λŒ€ν•œ 정보가 κΈ°λ‘λ˜λ„λ‘ ν•΄λ†“μ•˜λ‹€. λ°°μ—΄ times에 μ–΄λ–€ 값이 μ €μž₯λ˜λŠ”μ§€ μ•Œμ•„λ³΄μž.

let start = Date.now();
let times = [];

setTimeout(function run() {
// 이전 호좜이 λλ‚œ μ‹œμ κ³Ό ν˜„μž¬ 호좜이 μ‹œμž‘λœ μ‹œμ μ˜ μ‹œμ°¨λ₯Ό 기둝.
times.push(Date.now() - start);

// 지연 간격이 100msλ₯Ό λ„˜μ–΄κ°€λ©΄, arrayλ₯Ό μ–ΌλŸΏμ°½μ— λ„μ›Œμ€Œ.
if(start + 100 < Date.now()) alert(times);
	// 지연 간격이 100msλ₯Ό λ„˜μ–΄κ°€μ§€ μ•ŠμœΌλ©΄ μž¬μŠ€μΌ€μ€„λ§ν•¨.
else setTimeout(run);
});

// 좜λ ₯μ°½ μ˜ˆμ‹œ:
// 1,1,1,1,5,10,14,19,23,29,33,39,42,47,52,56,61,67,72,77,83,88,93,96,102

초기 타이머듀은(μŠ€νŽ™μ— 적힌 κ²ƒμ²˜λŸΌ) 지연 없이 λ°”λ‘œ μ‹€ν–‰λœλ‹€. 그런데 λ‹€μ„―λ²ˆ μ§Έ 쀑첩 타이머 이후엔 지연 간격이 4λ°€λ¦¬μ΄ˆ 이상이 λ˜μ–΄ 5,10,14,19..와 같은 값이 μ €μž₯λ˜λŠ” 것을 λ³Ό 수 μžˆλ‹€.

이런 μ œμ•½ 사항은 setTimeout뿐만 μ•„λ‹ˆλΌ setInterval에도 μ μš©λœλ‹€. setInterval(f)도 처음 λͺ‡ λ²ˆμ€ ν•¨μˆ˜ fλ₯Ό 지연없이 μ‹€ν–‰ν•˜μ§€λ§Œ, λ‚˜μ€‘μ—” 지연 간격을 4λ°€λ¦¬μ΄ˆ μ΄μƒμœΌλ‘œ λŠ˜λ €λ²„λ¦°λ‹€.

μ΄λŠ” μ˜€λž˜μ „λΆ€ν„° 있던 μ œμ•½μΈλ°, ꡬ식 슀크립트 쀑 μΌλΆ€λŠ” 아직 이 μ œμ•½μ— μ˜μ‘΄ν•˜λŠ” κ²½μš°κ°€ μžˆμ–΄μ„œ μŠ€νŽ™λ„ 이 μ œμ•½μ‚¬ν•­μ„ λ³€κ²½ν•˜μ§€ μ•Šκ³  λͺ…μ‹œν•˜κ³  μžˆλ‹€

ν•œνŽΈ, μ„œλ²„μΈ‘μ—” 이런 μ œμ•½μ΄ μ—†λ‹€. Node.js의 process.nextTickκ³Ό setImmediateλ₯Ό μ΄μš©ν•˜λ©΄ 비동기 μž‘μ—…μ„ 지연 없이 μ‹€ν–‰ν•  수 μžˆλ‹€. μœ„μ—μ„œ μ–ΈκΈ‰λœ μ œμ•½μ€ λΈŒλΌμš°μ €μ— ν•œμ •λœλ‹€.

 

μš”μ•½

  • setInterval(func, delay, ..args)κ³Ό setTimeout(func, delay, ..args)은 delayλ°€λ¦¬μ΄ˆ 후에 func을 κ·œμΉ™μ μœΌλ‘œ, λ˜λŠ” ν•œλ²ˆ μ‹€ν–‰ν•˜λ„λ‘ ν•΄μ€€λ‹€.
  • setInterval / setTimeout을 ν˜ΈμΆœν•˜κ³  λ°˜ν™˜λ°›μ€ 값을 clearInterval / clearTimeout에 λ„˜κ²¨μ£Όλ©΄ μŠ€μΌ€μ€„λ§μ„ μ·¨μ†Œν•  수 μžˆλ‹€.
  • 쀑첩 setTimeout을 μ‚¬μš©ν•˜λ©΄ setInterval을 μ‚¬μš©ν•œ 것보닀 μœ μ—°ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆλ‹€. 지연간격이 보μž₯λ˜λŠ” 것 λ˜ν•œ 이점이닀.
  • λŒ€κΈ°μ‹œκ°„μ΄ 0인 setTimeout(setTimeout(func, 0) μ΄λ‚˜ setTimeout(func))을 μ‚¬μš©ν•˜λ©΄ "ν˜„μž¬ 슀크립트의 싀행이 μ™„λ£Œλœ 후에 κ°€λŠ₯ν•œ λΉ λ₯΄κ²Œ" μ›ν•˜λŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  수 μžˆλ‹€.
  • 지연없이 쀑첩 setTimeoutμ—μ„œ 5회 이상 ν˜ΈμΆœν•˜κ±°λ‚˜ μ§€μ—°μ—†λŠ” setIntervalμ—μ„œ 호좜이 5νšŒμ΄μƒ μ§„ν–‰λ˜λ©΄, 4λ°€λ¦¬μ΄ˆ μ΄μƒμ˜ 지연 간격을 κ°•μ œμ μœΌλ‘œ 더해쀀닀. μ΄λŠ” λΈŒλΌμš°μ €μ—μ„œλ§Œ μ μš©λ˜λŠ” 사항이며, ν•˜μœ„ ν˜Έν™˜μ„±μ„ μœ„ν•΄ μœ μ§€λ˜κ³  μžˆλ‹€.

 

λͺ¨λ“  μŠ€μΌ€μ€„λ§ λ©”μ„œλ“œκ°€ λͺ…μ‹œν•œ 지연 간격을 보μž₯ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 점에 μœ μ˜ν•΄μ•Ό ν•œλ‹€.

μ•„λž˜μ™€ 같은 μƒν™©μ—μ„œ λΈŒλΌμš°μ € λ‚΄ 타이머가 λŠλ €μ§€λ©΄ 지연 간격이 보μž₯λ˜μ§€ μ•ŠλŠ”λ‹€.

  • CPUκ°€ κ³ΌλΆ€ν•˜ μƒνƒœμΈ 경우
  • λΈŒλΌμš°μ € 탭이 λ°±κ·ΈλΌμš΄λ“œ λͺ¨λ“œμΈ 경우
  • λ…ΈνŠΈλΆμ΄ 배터리에 μ˜μ‘΄ν•΄μ„œ ꡬ동쀑인 경우

이런 μƒν™©μ—μ„œ νƒ€μ΄λ¨Έμ˜ μ΅œμ†Œ 지연 μ‹œκ°„μ€ 300λ°€λ¦¬μ΄ˆμ—μ„œ μ‹¬ν•˜λ©΄ 1000λ°€λ¦¬μ΄ˆκΉŒμ§€ λŠ˜μ–΄λ‚œλ‹€. μ—°μž₯ μ‹œκ°„μ€ λΈŒλΌμš°μ €λ‚˜ ꡬ동쀑인 운영체제의 μ„±λŠ₯ 섀정에 따라 λ‹€λ₯΄λ‹€.

 

 

과제

μΌμ΄ˆκ°„κ²©μœΌλ‘œ 숫자 좜λ ₯ν•˜κΈ°

from에 λͺ…μ‹œν•œ μˆ«μžλΆ€ν„° to에 λͺ…μ‹œν•œ μˆ«μžκΉŒμ§€ 좜λ ₯ν•΄μ£ΌλŠ” ν•¨μˆ˜ printNumbers(from, to)λ₯Ό λ§Œλ“€μ–΄λ³΄μž. μˆ«μžλŠ” 일 초 κ°„κ²©μœΌλ‘œ 좜λ ₯λ˜μ–΄μ•Ό ν•œλ‹€.

두 가지 방법을 μ‚¬μš©ν•΄ λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.

  1. setInterval을 μ΄μš©ν•œ 방법
  2. 쀑첩setTimeout을 μ΄μš©ν•œ 방법

ν•΄λ‹΅ :

  1. setInterval을 μ΄μš©ν•œ 방법
    setInterval
function printNumbers(from, to) {
  let current = from;
  let timerId = setInterval(function() {
    alert(current);
    if(current === to) {
      clearInterval(timerId);
    }
    current++;
  }, 1000);
}

// usage:
printNumbers(5, 10);

 

  1. 쀑첩 setTimeout을 μ΄μš©ν•œ 방법
function printNumbers(from, to) {
  let current = from;
  setTimeout(function go() {
    alert(current);
    if(current < to) {
      setTimeout(go, 1000);
    }
    current++;
  }, 1000);
}

// usage:
printNumbers(5, 10);

두 방법 λͺ¨λ‘μ—μ„œ 졜초 호좜 이전에(첫 번째 μ–ΌλŸΏ 창이 뜨기 전에)1000ms의 지연 간격을 λ‘μ—ˆλ‹€λŠ” 점에 μ£Όλͺ©ν•˜κΈΈ λ°”λž€λ‹€.

초기 μ§€μ—°μ‹œκ°„ 없이 ν•¨μˆ˜λ₯Ό λ°”λ‘œ μ‹€ν–‰ν•˜λ €λ©΄ μ•„λž˜μ™€ 같이 λ³„λ„μ˜ μ€„μ—μ„œ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•΄μ€˜μ•Ό ν•œλ‹€.

function printNumbers(from, to) {
	let current = from;
  function go() {
    alert(current);
    if(current === to) {
      clearInterval(timerId);
    }
    current++;
  }
  go();
  let timerId = setInterval(go, 1000);
}
printNumbers(5, 10);

 

setTimeout은 무엇을 λ³΄μ—¬μ€„κΉŒ?

μ•„λž˜ μ½”λ“œμ—μ„  setTimeout을 μ΄μš©ν•΄ ν˜ΈμΆœμ„ μŠ€μΌ€μ€„λ§ν•˜κ³  μžˆλ‹€. 그런데 κ·Έ μ•„λž˜ μ½”λ“œμ—μ„  μ‹€ν–‰ μ‹œκ°„μ΄ 100ms이상 κ±Έλ¦¬λŠ” 무거운 μž‘μ—…μ„ ν•˜κ³  μžˆλ‹€.

이런 경우 setTimeout에 λ„˜κ²¨μ€€ ν•¨μˆ˜λŠ” μ–Έμ œ μ‹€ν–‰λ κΉŒ?

  1. 반볡문 μ‹€ν–‰ ν›„
  2. 반볡문 μ‹€ν–‰ μ „
  3. 반볡문이 μ‹€ν–‰λ˜λŠ” μ‹œμ 

μ–ΌλŸΏμ°½μ—” μ–΄λ–€ 값이 좜λ ₯될까?

let i = 0;
setTImeout(() => alert(i), 100); // ?

// μ•„λž˜ λ°˜λ³΅λ¬Έμ„ λ‹€ λ„λŠ”λ° 100ms μ΄μƒμ˜ μ‹œκ°„μ΄ κ±Έλ¦°λ‹€κ³  κ°€μ •.
for(let j = 0; j < 10000000; j++) {
  i++;
}

 

ν•΄λ‹΅ :

setTimeout은 ν˜„μž¬ 싀행쀑인 μ½”λ“œμ˜ 싀행이 μ’…λ£Œλ˜μ—ˆμ„ λ•Œ μ‹€ν–‰λœλ‹€.

반볡문 싀행이 μ’…λ£Œλ˜κ³  λ‚œ ν›„ iλŠ” 10000000이 λ˜λ―€λ‘œ, μ–ΌλŸΏ μ°½μ—” 10000000이 좜λ ₯λœλ‹€.

let i = 0;
setTimeout(() => alert(i), 100); // 10000000이 좜λ ₯λœλ‹€.

// assume that the time to execute this function is > 100ms
for(let j = 0; j < 10000000; j++) {
  i++;
}

 

 

λ°˜μ‘ν˜•