Appearance
Timer
- UI 에서 시간 관련 표시를 하게 되는 경우가 종종 있습니다.
- javascript 의 setTimeout, setInterval 은 정확한 실행 시간을 보장하지 않습니다.
- Timer 역시 정확한 실행 시점을 보장하긴 어려우나, (어느정도)초/분 단위 실행 시간이 보장 되도록 setTimeout 을 보완합니다.
- Timer 는 시간을 출력하기 위함이 아니라 정해진 간격 마다 알림을 주기 위한 용도로 만들어 졌습니다.
데모
SecondTimer 와 MinuteTimer 의 간단한 사용예 입니다.
- SecondTimer
- MinuteTimer
💡 아래 코드를 살펴보기 전 참고하세요.
- SecondTimer 와 MinuteTimer 의 차이는 실행 간격의 차이가 있습니다. SecondTimer 는 1초, MinuteTimer 는 1분의 간격으로 실행 됩니다.
- Timer 는 시간을 출력하기 위함이 아니라 정해진 간격 마다 알림을 주기 위한 용도로 만들어 졌습니다.
- 브라우저의 비활성화(sleep) 상태와 같이 타이머의 업데이트가 화면에 표시가 된다는것을 보장하기 어려운 경우가 있습니다. SecondTimer 의 경우 실행 간격이 짧기 때문에 금새 화면이 업데이트 되어 문제를 알아차리기 어렵지만, MinuteTimer 의 경우 실행 간격이 길기 때문에 비활성 상태에 빠져있던 경우 화면에 업데이트 되기까지 MinuteTimer 의 실행 간격인 최대 1분이 걸릴 수 있습니다. 이 점을 보완하기 위해 Visibility API 와 같이 화면이 활성화 되는 시점을 할 수 있다면 직접 업데이트를 해주는것도 좋습니다.
vue
<template>
<div>
<div class="times">
<dl class="time">
<dt>SecondTimer</dt>
<dd>{{ viewState.labelSecondTimer }}</dd>
</dl>
<dl class="time">
<dt>MinuteTimer</dt>
<dd>{{ viewState.labelMinuteTimer }}</dd>
</dl>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, onMounted, onUnmounted, reactive } from 'vue';
import { SecondTimer, MinuteTimer } from '@jood/helpdesk-module/timer';
import { Subscription } from 'rxjs';
export default defineComponent({
setup() {
const serverTime = Date.now();
const secondTimer = new SecondTimer();
const minuteTimer = new MinuteTimer();
const listener = new Subscription();
const state = reactive({
secondDate: null,
minuteDate: null,
});
const viewState = computed(() => {
const { secondDate, minuteDate } = state;
const labelSecondTimer = secondDate?.toLocaleString() || '';
const labelMinuteTimer = minuteDate?.toLocaleString() || '';
return {
labelSecondTimer,
labelMinuteTimer,
};
});
const onSecondUpdated = () => {
updateSecondTimer();
};
const onMinuteUpdated = () => {
updateMinuteTimer();
};
const updateSecondTimer = () => {
const timeAt = serverTime + secondTimer.getExecuteGap();
state.secondDate = new Date(timeAt);
};
const updateMinuteTimer = () => {
const timeAt = serverTime + minuteTimer.getExecuteGap();
state.minuteDate = new Date(timeAt);
};
onMounted(() => {
listener.add(secondTimer.observe().subscribe(onSecondUpdated));
secondTimer.start();
listener.add(minuteTimer.observe().subscribe(onMinuteUpdated));
minuteTimer.start();
updateSecondTimer();
updateMinuteTimer();
});
onUnmounted(() => {
secondTimer.stop();
minuteTimer.stop();
listener.unsubscribe();
});
return {
state,
viewState,
};
},
});
</script>
시간 출력을 업데이트 하는 부분을 살펴보세요. getExecuteGap
은 Timer 가 start 된 후 지나간 시간 입니다.
typescript
const updateSecondTimer = () => {
const timeAt = serverTime + secondTimer.getExecuteGap();
state.secondDate = new Date(timeAt);
};
클라이언트 시간만으로는 PC/디바이스 시간 설정에 영향을 받는 문제로 (데모에서는 Date.now() 를 사용했지만) serverTime 을 내려받은 시간을 기준으로 카운트 다운을 한다거나 지나간 시간을 표시하는 사례는 종종 있습니다. 이런 경우 getExecuteGap
를 사용하면 됩니다. timezone 과 같은 문제를 다루는건 사용자의 몫 입니다.