Skip to content

Commit

Permalink
docs: 41장 정리
Browse files Browse the repository at this point in the history
  • Loading branch information
e6d1fe committed Feb 5, 2024
1 parent f7141e1 commit 1c80823
Showing 1 changed file with 116 additions and 0 deletions.
116 changes: 116 additions & 0 deletions docs/41_타이머/나세현.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
## 41장 타이머

### 📍 41.1: 호출 스케줄링

호출 스케줄링: 함수를 명시적으로 호출하지 않고 일정 시간이 경과된 이후에 호출되도록 함수 호출을 예약하는 것 (타이머 함수 사용)

자바스크립트는 타이머를 생성할 수 있는 함수 `setTimeout과` `setInterval`, 그리고 타이머를 제거할 수 있는 함수 `clearTimeout과` `clearInterval을` 제공한다.
해당 함수들은 ECMAScript 사양에 정의된 빌트인 함수가 아니고, 브라우저와 Node.js 환경에서 모두 전역 객체의 메서드로서 제공된다.
`setTimeout` 함수의 콜백 함수는 타이머가 만료되면 단 한 번 호출되고, `setInterval` 함수의 콜백 함수는 타이머가 만료될 때마다 반복 호출된다.
두 함수 모두 비동기 처리 방식으로 동작한다.

### 📍 41.2: 타이머 함수

#### `setTimeout` / `clearTimeout`

`setTimeout` 함수는 두번째 인수로 전달받은 시간(ms 단위)으로 단 한 번 동작하는 타이머를 생성한다.
이후 타이머가 만료되면 첫번째 인수로 전달받은 콜백 함수가 호출된다.
생성된 타이머를 식별할 수 있는 고유한 타이머 `id`를 반환하며, 이 `id`는 브라우저 환경인 경우 숫자이고 Node.js 환경인 경우 객체다.
`setTimeout` 함수가 반환한 타이머 `id``clearTimeout` 함수의 인수로 전달하여 타이머를 취소할 수 있다.

```javascript
const timerId = setTimeout(() => console.log('Timer'), 1000);
// 1초 후 타이머가 만료되면 콜백 함수 호출

clearTimeout(timerId);
```

#### `setInterval` / `clearInterval`

`setInterval` 함수는 두번째 인수로 전달받은 시간(ms 단위)으로 반복 동작하는 타이머를 생성한다.
이후 타이머가 만료될 때마다 첫번째 인수로 전달받은 콜백 함수가 반복 호출되며, 타이머가 취소될 때까지 계속된다.
`setInterval` 함수는 타이머 `id`를 반환하며 이는 브라우저 환경인 경우 숫자, Node.js 환경인 경우 객체다.

```javascript
let count = 0;

const timerId = setInterval(() => {
console.log(count);
if (count++ == 5) clearInterval(timerId);
}, 1000);
```

### 📍 41.3: 디바운스와 스로틀

`scroll`, `resize`, `input`, `mousemove` 같이 짧은 시간 간격으로 연속해서 발생하는 이벤트에 바인딩된 이벤트 핸들러는 과도하게 호출되어 성능에 문제를 일으킬 수 있다.
디바운스와 스로틀은 이런 이벤트를 그룹화해서 과도한 이벤트 핸들러의 호출을 방지하는 프로그래밍 기법이다.
디바운스와 스로틀의 구현에는 타이머 함수가 사용된다.

#### 디바운스

짧은 시간 간격으로 이벤트가 연속해서 발생하면 이벤트 핸들러를 호출하지 않다가 일정 시간이 경과한 이후에 이벤트 핸들러가 한 번만 호출되도록 한다.
즉, 디바운스는 짧은 시간 간격으로 발생하는 이벤트를 그룹화해서 마지막에 한 번만 이벤트 핸들러가 호출되도록 한다.

```html
<!DOCTYPE html>
<html>
<body>
<input type="text" />
<div class="msg"></div>
<script>
const $input = document.querySelector('.input');
const $msg = document.querySelector('.msg');
const debounce = (callback, delay) => {
let timerId;
// debounce 함수는 timerId를 기억하는 클로저를 반환
return (...args) => {
if (timerId) clearTimeout(timerId);
timerId = setTimeout(callback, delay, ...args);
};
};
$input.oninput = debounce((e) => {
$msg.textContent = e.target.value;
}, 300);
</script>
</body>
</html>
```

`debounce` 함수가 반환한 함수는 `debounce` 함수에 두번째 인수로 전달한 시간보다 짧은 간격으로 이벤트가 발생하면 이전 타이머를 취소하고 새로운 타이머를 재설정한다.
따라서 `delay`보다 짧은 간격으로 이벤트가 연속해서 발생하면 첫번째 인수로 전달한 콜백 함수는 호출되지 않다가 `delay` 동안 `input` 이벤트가 발생하지 않으면 한 번만 호출된다.
이처럼 짧은 시간 간격으로 이벤트가 연속해서 발생하면 이벤트 핸들러를 호출하지 않다가 일정 시간 동안 이벤트가 더 이상 발생하지 않으면 이벤트 핸들러가 한 번만 호출되도록 하는 디바운스는 **`resize` 이벤트 처리나 `input` 요소에 입력된 값으로 `ajax` 요청하는 입력 필드 자동완성 UI 구현, 버튼 중복 클릭 방지 처리 등에 유용하게 사용된다**.
위 예제의 `debounce` 함수는 간략하게 구현한 것으로 완벽하지 않고, 실무에서는 Underscore/Lodash의 `debounce` 함수를 사용하는 것을 권장한다.

#### 스로틀

짧은 시간 간격으로 이벤트가 연속해서 발생하더라도 일정 시간 간격으로 이벤트 핸들러가 최대 한 번만 호출되도록 한다.
즉, 스로틀은 짧은 시간 간격으로 연속해서 발생하는 이벤트를 그룹화해서 일정 시간 단위로 이벤트 핸들러가 호출되도록 호출 주기를 만든다.

```javascript
const throttle = (callback, delay) => {
let timerId;

return (...args) => {
if (timerId) return;
timerId = setTimeout(() => {
callback(...args);
timerId = null;
}, delay);
};
};

$container.addEventListener(
'scroll',
throttle(() => {
$throttleCount.textContent = ++throttleCount;
}, 100)
);
```

`throttle` 함수가 반환한 함수는 `delay`가 경과하기 이전에 이벤트가 발생하면 아무것도 하지 않다가 시간이 경과했을 때 이벤트가 발생하면 콜백 함수를 호출하고 새로운 타이머를 재설정한다.
따라서 `delay` 간격으로 콜백 함수가 호출된다.
이처럼 짧은 시간 간격으로 연속해서 발생하는 이벤트를 그룹화해서 일정 시간 간격으로 이벤트 핸들러를 호출하는 스로틀은 `scroll` 이벤트 처리나 무한 스크롤 UI 구현 등에 유용하게 사용된다.
위 예제의 `throttle` 함수는 간략하게 구현한 것으로 완벽하지 않고, 실무에서는 Underscore/Lodash의 `throttle` 함수를 사용하는 것을 권장한다.

0 comments on commit 1c80823

Please sign in to comment.