From d9ae7578ceae0c4d7433ac48f017ce38ca3af608 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Sat, 25 Apr 2026 00:17:47 +0800 Subject: [PATCH] perf: reduce traffic update allocations --- src/components/layout/traffic-graph.tsx | 63 ++++++++++++++----------- src/hooks/use-memory-data.ts | 23 +++++++++ src/hooks/use-traffic-data.ts | 23 +++++++++ 3 files changed, 82 insertions(+), 27 deletions(-) diff --git a/src/components/layout/traffic-graph.tsx b/src/components/layout/traffic-graph.tsx index d8a1a0b46..17d2b04be 100644 --- a/src/components/layout/traffic-graph.tsx +++ b/src/components/layout/traffic-graph.tsx @@ -20,6 +20,8 @@ export interface TrafficRef { toggleStyle: () => void } +type TrafficValueKey = 'up' | 'down' + /** * draw the traffic graph */ @@ -101,42 +103,49 @@ export function TrafficGraph({ ref }: { ref?: Ref }) { return 1 } - const drawBezier = (list: number[], offset: number) => { - const points = list.map((y, i) => [ - (dx * (i - 1) - offset + 3) | 0, - countY(y), - ]) + const drawBezier = ( + list: Traffic[], + valueKey: TrafficValueKey, + offset: number, + ) => { + if (list.length === 0) return - context.moveTo(points[0][0], points[0][1]) + const firstX = (dx * -1 - offset + 3) | 0 + const firstY = countY(list[0]?.[valueKey] ?? 0) - for (let i = 1; i < points.length; i++) { - const p1 = points[i] - const p2 = points[i + 1] || p1 + context.moveTo(firstX, firstY) - const x1 = (p1[0] + p2[0]) / 2 - const y1 = (p1[1] + p2[1]) / 2 + for (let i = 1; i < list.length; i++) { + const p1x = (dx * (i - 1) - offset + 3) | 0 + const p1y = countY(list[i]?.[valueKey] ?? 0) - context.quadraticCurveTo(p1[0], p1[1], x1, y1) + const hasNext = i + 1 < list.length + const p2x = hasNext ? (dx * i - offset + 3) | 0 : p1x + const p2y = hasNext ? countY(list[i + 1]?.[valueKey] ?? 0) : p1y + + context.quadraticCurveTo(p1x, p1y, (p1x + p2x) / 2, (p1y + p2y) / 2) } } - const drawLine = (list: number[], offset: number) => { - const points = list.map((y, i) => [ - (dx * (i - 1) - offset) | 0, - countY(y), - ]) + const drawLine = ( + list: Traffic[], + valueKey: TrafficValueKey, + offset: number, + ) => { + if (list.length === 0) return - context.moveTo(points[0][0], points[0][1]) + context.moveTo((dx * -1 - offset) | 0, countY(list[0]?.[valueKey] ?? 0)) - for (let i = 1; i < points.length; i++) { - const p = points[i] - context.lineTo(p[0], p[1]) + for (let i = 1; i < list.length; i++) { + context.lineTo( + (dx * (i - 1) - offset) | 0, + countY(list[i]?.[valueKey] ?? 0), + ) } } const drawGraph = (lastTime: number) => { - const listUp = listRef.current.map((v) => v.up) - const listDown = listRef.current.map((v) => v.down) + const list = listRef.current const lineStyle = styleRef.current const now = Date.now() @@ -168,9 +177,9 @@ export function TrafficGraph({ ref }: { ref?: Ref }) { context.lineWidth = upLineWidth context.strokeStyle = upLineColor if (lineStyle) { - drawBezier(listUp, offset) + drawBezier(list, 'up', offset) } else { - drawLine(listUp, offset) + drawLine(list, 'up', offset) } context.stroke() context.closePath() @@ -180,9 +189,9 @@ export function TrafficGraph({ ref }: { ref?: Ref }) { context.lineWidth = downLineWidth context.strokeStyle = downLineColor if (lineStyle) { - drawBezier(listDown, offset) + drawBezier(list, 'down', offset) } else { - drawLine(listDown, offset) + drawLine(list, 'down', offset) } context.stroke() context.closePath() diff --git a/src/hooks/use-memory-data.ts b/src/hooks/use-memory-data.ts index d2734fda8..e629ce9e4 100644 --- a/src/hooks/use-memory-data.ts +++ b/src/hooks/use-memory-data.ts @@ -8,6 +8,26 @@ export interface IMemoryUsageItem { } const FALLBACK_MEMORY_USAGE: IMemoryUsageItem = { inuse: 0 } +const DUPLICATE_MEMORY_WINDOW_MS = 50 + +let lastMemorySignature = '' +let lastMemoryTimestamp = 0 + +const shouldSkipDuplicateMemory = (memory: IMemoryUsageItem) => { + const now = Date.now() + const signature = `${memory.inuse}:${memory.oslimit ?? ''}` + + if ( + signature === lastMemorySignature && + now - lastMemoryTimestamp <= DUPLICATE_MEMORY_WINDOW_MS + ) { + return true + } + + lastMemorySignature = signature + lastMemoryTimestamp = now + return false +} export const useMemoryData = () => { const { response, refresh } = useMihomoWsSubscription({ @@ -26,6 +46,9 @@ export const useMemoryData = () => { try { const parsed = JSON.parse(data) as IMemoryUsageItem + if (shouldSkipDuplicateMemory(parsed)) { + return + } next(null, parsed) } catch (error) { next(error, FALLBACK_MEMORY_USAGE) diff --git a/src/hooks/use-traffic-data.ts b/src/hooks/use-traffic-data.ts index 70926bf39..e9bc8245b 100644 --- a/src/hooks/use-traffic-data.ts +++ b/src/hooks/use-traffic-data.ts @@ -4,6 +4,26 @@ import { useMihomoWsSubscription } from './use-mihomo-ws-subscription' import { useTrafficMonitorEnhanced } from './use-traffic-monitor' const FALLBACK_TRAFFIC: Traffic = { up: 0, down: 0 } +const DUPLICATE_TRAFFIC_WINDOW_MS = 50 + +let lastTrafficSignature = '' +let lastTrafficTimestamp = 0 + +const shouldSkipDuplicateTraffic = (traffic: Traffic) => { + const now = Date.now() + const signature = `${traffic.up}:${traffic.down}` + + if ( + signature === lastTrafficSignature && + now - lastTrafficTimestamp <= DUPLICATE_TRAFFIC_WINDOW_MS + ) { + return true + } + + lastTrafficSignature = signature + lastTrafficTimestamp = now + return false +} export const useTrafficData = (options?: { enabled?: boolean }) => { const enabled = options?.enabled ?? true @@ -27,6 +47,9 @@ export const useTrafficData = (options?: { enabled?: boolean }) => { try { const parsed = JSON.parse(data) as Traffic + if (shouldSkipDuplicateTraffic(parsed)) { + return + } appendData(parsed) next(null, parsed) } catch (error) {