perf: ⚡ use setInterval instead of setTimeout chain in MkTime
This commit is contained in:
parent
be83ac8f43
commit
c462d48bdb
2 changed files with 60 additions and 21 deletions
|
@ -1,21 +1,23 @@
|
|||
<template>
|
||||
<time :title="absolute">
|
||||
<template v-if="mode === 'relative'">{{ relative }}</template>
|
||||
<template v-if="invalid">{{ i18n.ts._ago.invalid }}</template>
|
||||
<template v-else-if="mode === 'relative'">{{ relative }}</template>
|
||||
<template v-else-if="mode === 'absolute'">{{ absolute }}</template>
|
||||
<template v-else-if="mode === 'detail'"
|
||||
>{{ absolute }} ({{ relative }})</template
|
||||
>
|
||||
<slot></slot>
|
||||
</time>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onUnmounted } from "vue";
|
||||
import { onMounted, onUnmounted } from "vue";
|
||||
import { i18n } from "@/i18n";
|
||||
import { dateTimeFormat } from "@/scripts/intl-const";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
time: Date | string;
|
||||
time: Date | string | number | null;
|
||||
origin?: Date | null;
|
||||
mode?: "relative" | "absolute" | "detail";
|
||||
}>(),
|
||||
{
|
||||
|
@ -24,12 +26,23 @@ const props = withDefaults(
|
|||
);
|
||||
|
||||
const _time =
|
||||
typeof props.time === "string" ? new Date(props.time) : props.time;
|
||||
const absolute = _time.toLocaleString();
|
||||
props.time == null
|
||||
? NaN
|
||||
: typeof props.time === "number"
|
||||
? props.time
|
||||
: (props.time instanceof Date
|
||||
? props.time
|
||||
: new Date(props.time)
|
||||
).getTime();
|
||||
const invalid = Number.isNaN(_time);
|
||||
const absolute = !invalid ? dateTimeFormat.format(_time) : i18n.ts._ago.invalid;
|
||||
|
||||
let now = $shallowRef(new Date());
|
||||
const relative = $computed(() => {
|
||||
const ago = (now.getTime() - _time.getTime()) / 1000; /*ms*/
|
||||
let now = $ref((props.origin ?? new Date()).getTime());
|
||||
const relative = $computed<string>(() => {
|
||||
if (props.mode === "absolute") return ""; // absoluteではrelativeを使わないので計算しない
|
||||
if (invalid) return i18n.ts._ago.invalid;
|
||||
|
||||
const ago = (now - _time) / 1000; /*ms*/
|
||||
return ago >= 31536000
|
||||
? i18n.t("_ago.yearsAgo", { n: Math.round(ago / 31536000).toString() })
|
||||
: ago >= 2592000
|
||||
|
@ -49,22 +62,36 @@ const relative = $computed(() => {
|
|||
: i18n.ts._ago.future;
|
||||
});
|
||||
|
||||
function tick() {
|
||||
// TODO: パフォーマンス向上のため、このコンポーネントが画面内に表示されている場合のみ更新する
|
||||
now = new Date();
|
||||
|
||||
tickId = window.setTimeout(() => {
|
||||
window.requestAnimationFrame(tick);
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
let tickId: number;
|
||||
|
||||
if (props.mode === "relative" || props.mode === "detail") {
|
||||
tickId = window.requestAnimationFrame(tick);
|
||||
function tick() {
|
||||
const _now = new Date().getTime();
|
||||
const agoPrev = (now - _time) / 1000; /*ms*/ // 現状のinterval
|
||||
|
||||
now = _now;
|
||||
|
||||
const ago = (now - _time) / 1000; /*ms*/ // 次のinterval
|
||||
const prev = agoPrev < 60 ? 10000 : agoPrev < 3600 ? 60000 : 180000;
|
||||
const next = ago < 60 ? 10000 : ago < 3600 ? 60000 : 180000;
|
||||
|
||||
if (!tickId) {
|
||||
tickId = window.setInterval(tick, next);
|
||||
} else if (prev < next) {
|
||||
window.clearInterval(tickId);
|
||||
tickId = window.setInterval(tick, next);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!invalid &&
|
||||
props.origin === null &&
|
||||
(props.mode === "relative" || props.mode === "detail")
|
||||
) {
|
||||
onMounted(() => {
|
||||
tick();
|
||||
});
|
||||
onUnmounted(() => {
|
||||
window.cancelAnimationFrame(tickId);
|
||||
if (tickId) window.clearInterval(tickId);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
|
12
packages/client/src/scripts/intl-const.ts
Normal file
12
packages/client/src/scripts/intl-const.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { lang } from "@/config";
|
||||
|
||||
export const versatileLang = (lang ?? "ja-JP").replace("ja-KS", "ja-JP");
|
||||
export const dateTimeFormat = new Intl.DateTimeFormat(versatileLang, {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
second: "numeric",
|
||||
});
|
||||
export const numberFormat = new Intl.NumberFormat(versatileLang);
|
Loading…
Reference in a new issue