๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŒŒ | WEB DEV/React

[React/JS] setTimeout, setInterval ์€ ์ „ํ˜€ "์‹œ๊ณ„" ํ•˜์ง€ ์•Š์•„ (setTimeout, setInterval ์˜ค๋ฅ˜)

by KASSID 2024. 1. 6.

ํ”„๋กœ์ ํŠธ์— ์‚ฝ์ž…ํ•  ์Šคํ†ฑ์›Œ์น˜ ๋งŒ๋“ค์–ด ๋†“์•˜๋‹ค.

6์ดˆ๋ฅผ ์„ธ์–ด๋ณด๋Š”๋ฐ ์ด์ƒํ•˜๊ฒŒ ์ฒด๊ฐ ์ƒ 8์ดˆ๋Š” ๋˜๋Š” ๊ฒƒ ๊ฐ™์•˜๋‹ค.

์•„ ์ด๊ฑฐ ์ด์ƒํ•œ๋ฐ??

 

1. setInetval์„ ํ™œ์šฉํ•œ ํƒ€์ด๋จธ

1) ์ž‘์„ฑ ์ฝ”๋“œ

๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋Š” setInterval์„ ์ด์šฉํ•˜์—ฌ ์ฃผ๊ธฐ์ ์œผ๋กœ ์‹œ๊ฐ„state๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๋ฐฉ์‹์ด๋‹ค.

const [run, setRun] = useState(); //์Šคํ†ฑ์›Œ์น˜start์ƒํƒœ
const [time, setTime] = useState(0); //์‹œ๊ฐ„state
const intervalRef = useRef();

//์‹œ์ž‘์ƒํƒœ ๊ฐ์ง€
useEffect(()=>{
  if(props.start){
    setRun(true);
  }
  else{
    clearInterval(intervalRef.current)
    setRun(false);
  }
},[props.start])

//์‹œ๊ฐ„ ์ฆ๊ฐ€ ๊ธฐ๋Šฅ
useEffect(()=>{
  if(run){
    intervalRef.current = setInterval(() => {
      setTime(val=>val+10);
  },10);
}
},[run])

//์ผ์ • ์‹œ๊ฐ„ ์ง€๋‚˜๋ฉด stop & ๋Ÿฐํƒ€์ž„ ์ •๋ณด ์ €์žฅ
useEffect(()=>{
  if(time == props.stop*1000+1){
    clearInterval(intervalRef.current)
    setRun(false);
  }
  else{
    props.setRunTime(time)
  }
})

 

์ด ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•˜์˜€์„๋•Œ ์ •ํ™•ํ•œ ์‹œ๊ฐ„์„ ๋ณด์žฅํ•˜์ง€ ์•Š๊ณ  ๋ฐ€๋ฆฌ๋Š” ํ˜„์ƒ์ด ์ผ์–ด๋‚ฌ๋‹ค.

 

2) ์˜ค๋ฅ˜์˜ ์›์ธ

setTimeout๊ณผ setInterval์€ Web API ์—์„œ ๋ณ„๋„๋กœ ์‹คํ–‰๋œ๋‹ค.

๋”ฐ๋ผ์„œ ๋น„๋™๊ธฐ ์ž‘์—…์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ด๋‹ค. (์‹ฑ๊ธ€์Šค๋ ˆ๋“œ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ !)

ํ•˜์ง€๋งŒ, ๋งž๋‹ฅ๋œจ๋ ธ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ์‹œ๊ฐ„ ์ง€์—ฐ ํ˜„์ƒ์ด ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.

์ถœ์ฒ˜ : https://medium.com/@gemma.croad/understanding-the-javascript-runtime-environment-4dd8f52f6fca

 

์œ„์˜ ๊ทธ๋ฆผ์„ ์ฐธ๊ณ ํ•ด setTimeout, setInterval์˜ ์ฒ˜๋ฆฌ๊ณผ์ •์„ ์‚ดํŽด๋ณด์ž.

1. Web API์— setInetval์„ ์ด์šฉํ•ด ์„ค์ •ํ•œ N ms์˜ ์‹œ๊ฐ„์ด ์ง€๋‚œ ํ›„ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ผ๋Š” ๋ช…๋ น์„ ๋ณด๋‚ด๋ฉด

2. ํ•ด๋‹น ์‹œ๊ฐ„์„ ๋ณด๋‚ธ ํ›„ Callback Queue(Task Queue)์— ๋ณด๋‚ธ๋‹ค.

3. ์ดํ›„ Event Loop๋ฅผ ํ†ตํ•ด Call Stack์œผ๋กœ ์ด๋™ํ•˜๋Š”๋ฐ,

์ด๋•Œ, Call Stack์—์„œ ์ด๋ฏธ ์ž‘์—… ์ค‘์ธ ๊ฒƒ์ด ์กด์žฌํ•œ๋‹ค๋ฉด ์ฒ˜๋ฆฌ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ ํ›„ ์ด๋™ํ•˜๊ฒŒ๋œ๋‹ค.

๋”ฐ๋ผ์„œ ์„ค์ •ํ•œ ์‹œ๊ฐ„ + ์ฝœ๋ฐฑ ํ์—์„œ์˜ ๋Œ€๊ธฐ์‹œ๊ฐ„์ด ํ•„์š”ํ•œ ๊ฒƒ์ด๋‹ค.

 

๋•Œ๋ฌธ์— ํ•ญ์ƒ ์ •ํ™•ํ•œ ์‹œ๊ฐ„์„ ๋ณด์žฅํ•ด์ฃผ์ง€ ์•Š๋Š” ๋ฐฉ๋ฒ•์ธ ๊ฒƒ์ด๋‹ค.

 

 


2. Date๋ฅผ ์ด์šฉํ•œ ํƒ€์ด๋จธ

setInterval๊ณผ setTimeout์˜ delay์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š” ํƒ€์ด๋จธ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋Š”

Date๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

 

Date - JavaScript | MDN

JavaScript Date objects represent a single moment in time in a platform-independent format. Date objects encapsulate an integral number that represents milliseconds since the midnight at the beginning of January 1, 1970, UTC (the epoch).

developer.mozilla.org

 

์‹œ๊ฐ„์„ ์ถ”์ถœํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” Date ์ค‘

Date.now()๋Š” UTC 1970๋…„ 1์›” 1์ผ 0์‹œ 0๋ถ„ 0์ดˆ๋ถ€ํ„ฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ ํ˜„ ์‹œ์ ๊นŒ์ง€ ๊ฒฝ๊ณผ๋œ ms๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.
์ด๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฒฝ๊ณผ ์‹œ๊ฐ„์„ ๊ตฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

1_ ์‹œ์ž‘ํ•  ๋•Œ ํ•œ ๋ฒˆ ํ˜ธ์ถœ, ๋๋‚ ๋•Œ ํ•œ ๋ฒˆ ํ˜ธ์ถœ

 

2_ ๋๋‚œ ์‹œ๊ฐ„ - ์‹œ์ž‘ ์‹œ๊ฐ„ = ๊ฒฝ๊ณผ์‹œ๊ฐ„

 

์œ„ ๋ฐฉ๋ฒ•์„ ํ™œ์šฉํ•˜์—ฌ ํƒ€์ด๋จธ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

// ์‹œ์ž‘ ๋ฒ„ํŠผ -> ์‹œ์ž‘ ์ƒํƒœ ์„ค์ •
const [start, setStart] = useState(false);
// ํƒ€์ด๋จธ run ์ƒํƒœ
const [run, setRun] = useState(false);
// ์‹œ์ž‘์‹œ๊ฐ„
let startTimeRef = useRef(null);
// ์‹œ๊ฐ„ state
const [seconds, setSeconds] = useState(0);
const [millseconds10, setMillseconds10] = useState(0);
const [milliseconds1, setMilliseconds1] = useState(0);

useEffect(()=>{
    if(start){
      timerPlay(); // ์‹œ์ž‘์‹œ๊ฐ„ ์ €์žฅ ํ•จ์ˆ˜ ํ˜ธ์ถœ
      setRun(true); // run ์ƒํƒœ ์„ค์ •
    }
    else{
      clearInterval(intervalRef.current)
      setRun(false);
    }
  },[start])

  useEffect(()=>{
    if(run){
      intervalRef.current = setInterval(() => {
        const now = new Date(Date.now() - startTimeRef.current);
        if(now.getTime() == stop*1000+1){ //์„ค์ •ํ•œ ์‹œ๊ฐ„ ์ดˆ๊ณผ์‹œ ๋ฉˆ์ถค
          clearInterval(intervalRef.current)
          setRun(false);
        }
        else{
          setSeconds(now.getUTCSeconds()); //์ดˆ
          setMillseconds10(now.getUTCMilliseconds().toString()[0]); //๋ฐ€๋ฆฌ
          setMilliseconds1(now.getUTCMilliseconds().toString()[1]); //๋ฐ€๋ฆฌ
        }
      },10);
    }
  },[run])
  
  // ์‹œ์ž‘ ์‹œ๊ฐ„ ์„ค์ • ํ•จ์ˆ˜
  const timerPlay = ()=>{
    if (startTimeRef.current===null){startTimeRef.current = Date.now();}
  }

 

๋Œ“๊ธ€