본문 바로가기

DOM

DOM 기초(4) - setTimeout, setInterval, single thread, event loop

728x90
반응형

1) Javascript 동작방식

    1-1) setTimeout / setInterval
    1-2) single thread / event loop

    1-3) 동기와 비동기

2) 코드 실습

 

 

 

 

 

1) Javascript 동작방식

1-1) setTimeout / setInterval

setTimeout, setInterval의 경우, 엄밀히 따지면 DOM이 아니다!!

 

setTimeout, setInterval은 window(전역객체)에 포함되어 있다(window 객체 안에 있다)!!

즉, setTimeout, setInterval은 자바스크립트의 기본 스펙이 아니라 브라우저가 만들어 놓은 메서드(브라우저가 제공해주는 기능)이다!!

window.setTimeout

 

window.setTimeout(callback, 1000);
// callback: function >> 실행할 함수
// 1000: number >> 시간
// 위의 코드는 1초 뒤에 callback 함수를 실행시키라는 의미임!!

window.setInterval(callback, 1000);
// callback: function >> 실행할 함수
// 1000: number >> 시간
// 위의 코드는 1초마다 callback 함수를 실행시키라는 의미임!!

 

  • setTimeout : 2번째 인자값인 밀리세컨드(number)가 충족되었을 시 딱 한 번만 실행됨!!
  • setInterval : 2번째 인자값인 밀리세컨드(number)가 충족되었을 때마다 계속 실행됨!!

 

// window.setTimeout()


// 5초 뒤에 1을 console에 출력함
setTimeout(function () {
  console.log(1);
}, 5000); // setTimeout은 window 전역객체 안에 있으므로 window를 생략하고 바로 사용할 수 있음(브라우저에서 제공해주는 메서드!!)


// 1초마다 2를 계속 console에 출력함
setInterval(function () {
  console.log(2);
}, 1000);


console.log(1);
setTimeout(function () {
  console.log(2);
}, 1000);
console.log(3);

/*
출력 결과
1
3
2
*/


// 문제 예시
// 빨래 돌리고 10초
// 빨래 널고 5초
// 정육점 가서 소고기 사오기 30초

setTimeout(function () {
  console.log("빨래 돌리기");
}, 10 * 1000);
setTimeout(function () {
    console.log("빨래 널기");
  }, 5 * 1000);
setTimeout(function () {
  console.log("소고기 사오기");
}, 30 * 1000);

/*
출력 결과
빨래 널기
빨래 돌리기
소고기 사오기
*/

 

 


1-2) single thread / event loop

싱글 스레드(single thread) : 프로그램을 해석하는 사람(스레드)이 한 명이다라는 의미이다!!
자바스크립트의 경우, 스레드는 코드를 실질적으로 실행시켜주는 "콜스택"이다!!
만일 콜스택이 여러 개라고 한다면 이는 멀티 스레드 방식이라고 볼 수 있다!!

자바스크립트는 setTimeout, setInterval 등을 처리하기 위해 "백그라운드"라는 공간(코드를 해석하는 공간)을 만들어서 해당 코드들을 콜스택에서 백그라운드에 보내서 코드를 해석한 뒤 위의 메서드 인수 조건(밀리세컨드)이 충족되면 "태스크 큐(태스크 큐에 먼저 들어간 코드가 먼저 콜스택으로 넘어감!!)"로 넘어간 뒤 태스크 큐에 있다가 최종적으로 콜스택이 비어있는 것이 확인되면 그때 콜스택으로 넘어가 실행됨!!

태스크 큐에서 콜스택으로 넣는 것을 일명, "이벤트 루프(event loop)"라고 한다!!

코드를 해석하는 공간은 "콜스택"과 "백그라운드" 총 2개(즉, 코드를 해석하는 사람, 일명 스레드가 2개임을 의미함)이며,
이때 콜스택에서 처리되는 것을 동기, 백그라운드에서 처리되는 것을 비동기라 한다!!
단, 자바스크립트의 경우 우리가 조작할 수 있는 공간은 "콜스택" 하나 뿐이기에 멀티 스레드 방식처럼 동작함에도 불구하고 싱글 스레드로 본다!!


Event Loop
프로미스 객체
async/await

 

 

// 비동기를 동기처럼 동작하도록 코드를 짠 예시

// 콜백헬(callback hell)
console.log("시작");
setTimeout(function () {
  console.log("세탁기 돌림");

  setTimeout(function () {
    console.log("세탁기 완료");

    setTimeout(function () {
      console.log("빨래 널기");
      console.log("종료");
    }, 5 * 1000);
  }, 5 * 1000);

  setTimeout(function () {
    console.log("소고기 사오기");
  }, 3 * 1000);
}, 10 * 1000);

/*
출력 결과
시작
세탁기 돌림
소고기 사오기
세탁기 완료
빨래 널기
종료
*/


// 자바스크립트는 비동기적인 코드를 짤 수밖에 없기에
// ES6, ES7... 으로 점차 업그레이드되면서 callback hell을
// 해결할 수 있는 방법들(promise, async/await)을 제시하게 됨!!

// callback > promise > async/await의 순서로 차근차근 이해해야 함!!
// callback(callback hell 포함)
// promise
// async/await


console.log(1);
setTimeout(function () {
  console.log(2);
}, 0);
console.log(3);

/*
출력 결과
(중요!!) setTimeout의 밀리세컨드 인수가 0초라 하더라도 setTimeout은 실행 전에 반드시 백그라운드로 넘어가 해당 코드를 해석한 뒤 조건이 충족되면 태스크 큐로 넘어간 뒤 콜스택이 비어있는 것이 확인되면 그제서야 콜스택으로 넘어가 코드가 실행되기 때문이다!!
1
3
2
*/


let name;
setTimeout(function () {
  name = "sangbeom";
  console.log(2);
}, 0);

console.log(name); // 출력 결과: undefined >> 'sangbeom'이 뽑힌다고 예측할 확률이 높지만 실제로 setTimeout은 백그라운드로 넘어간 뒤 태스크 큐에 보내진 다음 콜스택이 비어있다는 것이 확인된 뒤에 콜스택으로 넘어가 실행되기에 console.log(name)이 그 사이에 먼저 찍혀서 선언만 되어있던 name을 출력하기에 undefined가 출력됨!!


let numb = 0;
const timeId = setInterval(function () {
  console.log(numb++);
  if (numb === 5) clearInterval(timeId);
}, 0);

// clearInterval() : 해당 setInterval를 백그라운드에서 완전히 삭제하여 setInterval의 실행을 완전히 종료시킴!!


// 콜백함수에 인자를 넣어주는 코드
setTimeout(
  function (name) {
    console.log(name);
  },
  1000,
  "sangbeom"
);
// 출력 결과(1초 뒤에 출력해 줌) : sangbeom


let num = 0;
let count = 0;
const timeId = setInterval(function () {
  console.log(num++);
  count++;
  if (num === 4) num = 0;
  if (count === 9) clearInterval(timeId);
}, 1000);

/*
출력 결과
0
1
2
3
0
1
2
3
0
*/

※ clearInterval() : 해당 setInterval를 백그라운드에서 완전히 삭제하여 setInterval의 실행을 완전히 종료시킴!!

 

 

 

1-3) 동기와 비동기

  • "동기"는 작업이 하나 끝나면 다음 작업을 수행하는 것인데, 즉 작업을 하나하나 순차적으로 처리하는 것(반드시 현재 수행 중인 작업이 완료된 뒤에 다음 작업을 순서대로 진행하는 것)을 의미함!!
  • "비동기"는 하나의 작업을 수행하면서 다른 작업을 수행할 수 있는 것, 즉 복수의 작업을 동시에 처리하는 것을 말함!!

 

(중요!!) setTimeout, setInterval은 비동기이다!!
setTimeout과 setInterval의 두 번째 인수값인 밀리 세컨드의 경우, 각각의 밀리 세컨드는 백그라운드에서 동시에 카운트된다!!

ex)
setTimeout(function(){}, 2000)
setTimeout(function(){}, 5000)
// >> 해당 코드들을 실행하는 데에 총 "5초"의 시간이 소요됨!!

 

 

 

 

2) 코드 실습

 

index.js

// setInterval를 활용하여 visual 만들기(background color가 서로 다른 5개의 li 태그를 3초마다 자동으로 바꾸는 코드)
// >> setInterval를 활용하여 1초마다 on을 옮겨주기
const a = document.querySelector(".a");
const b = document.querySelector(".b");
const c = document.querySelector(".c");
const d = document.querySelector(".d");
const e = document.querySelector(".e");

/*
let count = 0;
setInterval(function () {
  if (count === 0) {
    a.classList.add("on");
    b.classList.remove("on");
    c.classList.remove("on");
    d.classList.remove("on");
    e.classList.remove("on");
  } else if (count === 1) {
    a.classList.remove("on");
    b.classList.add("on");
    c.classList.remove("on");
    d.classList.remove("on");
    e.classList.remove("on");
  } else if (count === 2) {
    a.classList.remove("on");
    b.classList.remove("on");
    c.classList.add("on");
    d.classList.remove("on");
    e.classList.remove("on");
  } else if (count === 3) {
    a.classList.remove("on");
    b.classList.remove("on");
    c.classList.remove("on");
    d.classList.add("on");
    e.classList.remove("on");
  } else {
    a.classList.remove("on");
    b.classList.remove("on");
    c.classList.remove("on");
    d.classList.remove("on");
    e.classList.add("on");
  }

  if (++count === 5) count = 0;
}, 3000);
*/

/*
let count = 1;
setInterval(function () {
  if (count === 0) {
    a.classList.add("on");
    b.classList.remove("on");
    c.classList.remove("on");
    d.classList.remove("on");
    e.classList.remove("on");
  } else if (count === 1) {
    a.classList.remove("on");
    b.classList.add("on");
    c.classList.remove("on");
    d.classList.remove("on");
    e.classList.remove("on");
  } else if (count === 2) {
    a.classList.remove("on");
    b.classList.remove("on");
    c.classList.add("on");
    d.classList.remove("on");
    e.classList.remove("on");
  } else if (count === 3) {
    a.classList.remove("on");
    b.classList.remove("on");
    c.classList.remove("on");
    d.classList.add("on");
    e.classList.remove("on");
  } else {
    a.classList.remove("on");
    b.classList.remove("on");
    c.classList.remove("on");
    d.classList.remove("on");
    e.classList.add("on");
  }

  if (++count === 5) count = 0;
}, 3000);
*/

// 위의 코드 refactoring version(for문, if문 활용)
const arr = [a, b, c, d, e];
const elements = document.querySelectorAll("#visual > li");

let count = 1;
const intervalId = setInterval(function () {
  for (let i = 0; i < elements.length; i++) {
    if (i === count) {
      elements[i].classList.add("on");
    } else {
      elements[i].classList.remove("on");
    }
  }

  if (++count === 5) count = 0;
}, 3000);

 

 

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./public/css/index.css" />
  </head>
  <body>
    <ul id="visual">
      <li class="a on">1</li>
      <li class="b">2</li>
      <li class="c">3</li>
      <li class="d">4</li>
      <li class="e">5</li>
    </ul>
    <script src="./public/js/index.js" type="text/javascript"></script>
  </body>
</html>

 

 

index.css

* {
  margin: 0;
  padding: 0;
}

ul,
li {
  list-style: none;
}

#visual {
  position: relative;
  width: 100%;
  height: 500px;
}

#visual > li {
  position: absolute;
  width: 100%;
  height: 500px;
  opacity: 0;
}

#visual > li.on {
  opacity: 1;
  transition: all 1s;
}

#visual > li.a {
  background: red;
}

#visual > li.b {
  background: yellow;
}

#visual > li.c {
  background: green;
}

#visual > li.d {
  background: silver;
}

#visual > li.e {
  background: blue;
}