M5(T-M5-03): 高频出站节流——通用 Debouncer/Throttler + 网络变化防抖合并
- common 新增 Debouncer/Throttler 工具(不在桥核心按 handler 名节流,避免桥核心 感知能力,违反零感知约束;由 Provider 自治应用) - NetworkProvider:netAvailable/netLost/netCapabilitiesChange 三事件统一经 300ms 防抖,切网瞬间多次突发合并为一次出站;onBackground/onDestroy 取消待发 - 说明:连续定位已受系统 timeInterval:5(5s) 约束、Device 为被动查询,无需额外节流; lzyzsd 协议 _handleMessageFromNative 单条语义,不做跨条合并(保 H5 零改动) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b461b291f5
commit
0a372f1339
@@ -9,3 +9,4 @@ export { NavEvents, OpenGenericWebPayload, SwitchGamePayload, BackGamePayload }
|
||||
export { DIContainer, Factory } from './src/main/ets/di/DIContainer';
|
||||
export { ErrorCenter, ErrorStrategy, ErrorSink } from './src/main/ets/error/ErrorCenter';
|
||||
export { AppEnv } from './src/main/ets/env/AppEnv';
|
||||
export { Debouncer, Throttler } from './src/main/ets/util/Throttle';
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 节流 / 防抖工具(T-M5-03)。供高频出站源(如网络变化广播)合并突发、降低跨引擎调用次数。
|
||||
*
|
||||
* 不在桥核心做按 handler 名的节流(那会让桥核心感知具体能力,违反「桥核心零感知」约束);
|
||||
* 由各 Provider 自治决定对哪些可合并的状态广播应用本工具。
|
||||
*/
|
||||
|
||||
/** 防抖:连续触发只在最后一次后 delayMs 执行一次(合并突发,取最终状态)。 */
|
||||
export class Debouncer {
|
||||
private readonly delayMs: number;
|
||||
private timer: number = -1;
|
||||
|
||||
constructor(delayMs: number) {
|
||||
this.delayMs = delayMs;
|
||||
}
|
||||
|
||||
/** 触发:取消上一次待执行,重新计时;窗口静默 delayMs 后执行 action。 */
|
||||
run(action: () => void): void {
|
||||
this.cancel();
|
||||
this.timer = setTimeout(() => {
|
||||
this.timer = -1;
|
||||
action();
|
||||
}, this.delayMs);
|
||||
}
|
||||
|
||||
/** 取消未执行的回调(Provider 去激活/销毁时调用,防泄漏与打已弃桥)。 */
|
||||
cancel(): void {
|
||||
if (this.timer !== -1) {
|
||||
clearTimeout(this.timer);
|
||||
this.timer = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 限流:窗口 windowMs 内最多执行一次(leading),窗口内最后一次在窗口末补执行(trailing)。 */
|
||||
export class Throttler {
|
||||
private readonly windowMs: number;
|
||||
private last: number = 0;
|
||||
private timer: number = -1;
|
||||
private pending: (() => void) | undefined = undefined;
|
||||
|
||||
constructor(windowMs: number) {
|
||||
this.windowMs = windowMs;
|
||||
}
|
||||
|
||||
/** 触发:距上次执行 ≥ windowMs 立即执行;否则记为待执行,窗口末执行最后一次。 */
|
||||
run(action: () => void): void {
|
||||
const now: number = Date.now();
|
||||
const elapsed: number = now - this.last;
|
||||
if (elapsed >= this.windowMs) {
|
||||
this.last = now;
|
||||
action();
|
||||
return;
|
||||
}
|
||||
this.pending = action;
|
||||
if (this.timer === -1) {
|
||||
this.timer = setTimeout(() => {
|
||||
this.timer = -1;
|
||||
this.last = Date.now();
|
||||
const p = this.pending;
|
||||
this.pending = undefined;
|
||||
if (p !== undefined) {
|
||||
p();
|
||||
}
|
||||
}, this.windowMs - elapsed);
|
||||
}
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
if (this.timer !== -1) {
|
||||
clearTimeout(this.timer);
|
||||
this.timer = -1;
|
||||
}
|
||||
this.pending = undefined;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { connection } from '@kit.NetworkKit';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { BridgeController } from 'feature_bridge';
|
||||
import { InboundHandlers, OutboundHandlers } from 'contracts';
|
||||
import { Logger } from 'common';
|
||||
import { Logger, Debouncer } from 'common';
|
||||
import { CapabilityContext, CapabilityProvider } from '../core/CapabilityProvider';
|
||||
|
||||
/** 网络码(契约:1 无网 / 2 WiFi / 3 移动)。 */
|
||||
@@ -16,11 +16,16 @@ const NET_NONE: string = '1';
|
||||
const NET_WIFI: string = '2';
|
||||
const NET_MOBILE: string = '3';
|
||||
|
||||
/** 网络变化防抖窗口:切网瞬间 netAvailable/netCapabilitiesChange 常连发多次,合并为一次出站。 */
|
||||
const NET_DEBOUNCE_MS: number = 300;
|
||||
|
||||
export class NetworkProvider implements CapabilityProvider {
|
||||
readonly name: string = 'network';
|
||||
private readonly log: Logger = Logger.tag('NetworkProvider');
|
||||
private bridge: BridgeController | undefined = undefined;
|
||||
private conn: connection.NetConnection | undefined = undefined;
|
||||
/** T-M5-03:合并短时间内的多次网络变化,取最终状态后只出站一次。 */
|
||||
private readonly debouncer: Debouncer = new Debouncer(NET_DEBOUNCE_MS);
|
||||
|
||||
register(bridge: BridgeController, _ctx: CapabilityContext): void {
|
||||
this.bridge = bridge;
|
||||
@@ -40,10 +45,12 @@ export class NetworkProvider implements CapabilityProvider {
|
||||
|
||||
/** 槽去激活:注销网络变化订阅(非激活端不监听)。 */
|
||||
onBackground(): void {
|
||||
this.debouncer.cancel();
|
||||
this.unsubscribe();
|
||||
}
|
||||
|
||||
onDestroy(): void {
|
||||
this.debouncer.cancel();
|
||||
this.unsubscribe();
|
||||
}
|
||||
|
||||
@@ -78,9 +85,10 @@ export class NetworkProvider implements CapabilityProvider {
|
||||
try {
|
||||
const conn: connection.NetConnection = connection.createNetConnection();
|
||||
this.conn = conn;
|
||||
conn.on('netAvailable', () => this.broadcast());
|
||||
conn.on('netLost', () => this.bridge?.callHandler(OutboundHandlers.GetNetwork, NET_NONE));
|
||||
conn.on('netCapabilitiesChange', () => this.broadcast());
|
||||
// 三类事件统一经防抖 → broadcast 计算最终网络码后出站一次(netLost 时 hasDefaultNet=false→NET_NONE)
|
||||
conn.on('netAvailable', () => this.debouncer.run(() => this.broadcast()));
|
||||
conn.on('netLost', () => this.debouncer.run(() => this.broadcast()));
|
||||
conn.on('netCapabilitiesChange', () => this.debouncer.run(() => this.broadcast()));
|
||||
conn.register((e: BusinessError) => {
|
||||
if (e) {
|
||||
this.log.w(`net register failed: ${e.code} ${e.message}`);
|
||||
|
||||
Reference in New Issue
Block a user