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

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

by KASSID 2024. 1. 6.

๋ชฉ์ฐจ

    728x90

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

    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();}
      }

     

    ๋Œ“๊ธ€