# 폴링을 실시간 업데이트로 바꾸기

> 몇 초마다 API에 묻는 일을 멈추세요. 변화는 한 번만 보내 요청과 서버 부하를 줄이고, 생기는 즉시 화면에 보여 줍니다.

Source: https://hibira.io/ko/use-cases/replace-polling

많은 앱은 '물어봐서' 변화를 알아냅니다. 열려 있는 모든 페이지가 몇 초마다 API를 호출해 주문, 티켓, 리포트가 바뀌었는지 확인하는 것이죠. 대답은 거의 항상 '새로운 것 없음'인데도, 매번 요청 하나, 데이터베이스 쿼리 하나, 사용자 휴대폰의 배터리를 씁니다. 실제로 바뀐 내용도 다음 간격이 올 때까지 화면에 나오지 않습니다. Hibira를 쓰면 변화가 생길 때 서버가 한 번만 보내고, 그 데이터를 보여 주는 모든 페이지가 몇 밀리초 안에 갱신됩니다.

## 사용자가 얻는 것

- 최대 5초를 기다리지 않고, 변화가 생긴 순간 화면에 반영.
- 새로고침 없이 모든 탭이 항상 최신 상태.
- 휴대폰이 몇 초마다 쓸데없이 네트워크를 깨우지 않음.

## 폴링의 비용

1,000명이 페이지를 열어 두고 5초마다 폴링하면 한 시간에 720,000개의 요청이 됩니다. 그 한 시간 동안 데이터가 200번만 바뀌었다면, 요청의 99.97%는 새로운 내용이 없습니다. 푸시로 바꾸면 같은 한 시간이 200개의 메시지로 끝나고, API는 각 페이지의 첫 로딩만 처리하면 됩니다.

## 사용하는 기능

- **비공개 채널**(`private-order-42`): 페이지가 보여 주는 대상마다 하나씩 만들고 서버가 인가하므로, 사용자는 자기 데이터만 받습니다.
- 공식 서버 SDK의 **`trigger`**: 변경을 저장한 직후에 호출합니다.
- **`pusher:subscription_succeeded`**: 첫 연결과 재연결 때마다 발생하므로, 현재 상태를 불러오기에 딱 맞는 시점입니다.

```text
flow: 폴링은 묻고 또 묻고, 푸시는 변화마다 한 번만 보낸다
== 폴링
열려 있는 모든 페이지|5초마다 --GET /api/orders/42--> 내 API|대부분 '새로운 것 없음'
== 푸시
내 API|변경 저장 --`trigger()` 한 번--> *Hibira --WebSocket--> 그 데이터를 보여 주는 모든 페이지|즉시 갱신
```

## 1단계: 폴링 루프 찾기

보통 이런 모양입니다:

```js
setInterval(async () => {
  render(await fetch('/api/orders/42').then((r) => r.json()));
}, 5000);
```

## 2단계: 한 번 불러오고, 그다음엔 듣기

[JavaScript 가이드](https://hibira.io/ko/guides/javascript)대로 연결하고, 비공개 채널용 채널 인가 엔드포인트를 준비합니다. 구독이 준비되면 현재 상태를 불러오고, 이후에는 변화가 도착할 때마다 반영합니다:

```js
const load = async () => render(await fetch('/api/orders/42').then((r) => r.json()));

const channel = pusher.subscribe('private-order-42');
channel.bind('pusher:subscription_succeeded', load);
channel.bind('updated', (order) => render(order));
```

## 3단계: 저장할 때 변화 보내기

데이터가 바뀌는 곳(API 라우트, 워커, 관리자 작업, 웹훅)에서 쓰기가 성공한 뒤 발행합니다:

```js
app.patch('/api/orders/:id', requireLogin, async (req, res) => {
  const order = await db.orders.update(req.params.id, req.body);
  await pusher.trigger(`private-order-${order.id}`, 'updated', order);
  res.json(order);
});
```

## 4단계: 가벼운 안전장치 두기

재연결 후 구독이 다시 발생하므로, 연결이 끊겼던 동안의 빈틈은 `load()`가 이미 채워 줍니다. 브라우저가 백그라운드 탭을 멈추기도 하므로, 탭이 다시 보일 때 한 번 더 불러옵니다:

```js
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'visible') load();
});
```

## 팁

- 페이지가 다시 그리는 데 필요한 내용을 보내세요. 큰 데이터라면 ID와 버전만 보내고 나머지는 페이지가 가져오게 합니다.
- 같은 데이터가 초당 여러 번 바뀐다면 [실시간 대시보드](https://hibira.io/ko/use-cases/live-dashboards)처럼 묶어서 보내세요.
- 자주 바뀌는 목록은 행마다가 아니라 목록마다 채널 하나(`private-orders-team-7`)를 쓸 수 있습니다.
- 이벤트 크기는 요금제에 따라 다릅니다. [요금](https://hibira.io/ko/pricing)을 확인하세요.
- 발행 전에 몇 명이 보고 있는지 알고 싶다면 [접속자 수](https://hibira.io/ko/use-cases/online-user-counts)를 보세요.
