fix(sdk): stayIntervalMs边界守卫——0/NaN钳制下限防事件灌入
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
+3
-1
@@ -24,7 +24,9 @@ export interface StayOptions {
|
||||
}
|
||||
|
||||
export function startStayTracking(t: Transport, ps: PageSession, opts: StayOptions = {}): void {
|
||||
const stayIntervalMs = opts.stayIntervalMs ?? 15_000;
|
||||
// 边界守卫:0/负数等有限小值钳制下限 1s(防 setInterval 高频 cut 灌入事件);
|
||||
// NaN/Infinity 非有限值——NaN 绕过 ?? 的 nullish 判定直传,须显式回落默认 15s。
|
||||
const stayIntervalMs = Math.max(1_000, Number.isFinite(opts.stayIntervalMs) ? opts.stayIntervalMs! : 15_000);
|
||||
let intervalStart: number | null = null; // performance.now 基准;null=无 open 区间
|
||||
let lastCutEnd: number | null = null; // 最近一次 cut 的 perf 端点——重开回溯的钳制上界
|
||||
let lastAct = Date.now(); // 墙钟活动戳(沿 events.ts 冻结语义;页面加载即活动)
|
||||
|
||||
@@ -254,4 +254,34 @@ describe("stay / startStayTracking", () => {
|
||||
expect(stays[0].properties.active_ms).toBe(30_000); // 活动窗 [0,30s] 整段
|
||||
expect(stays[0].properties.flush_reason).toBe("periodic"); // 失活悬置属周期结算
|
||||
});
|
||||
|
||||
it("stayIntervalMs 边界守卫:NaN 回落默认 15s;0 钳制下限 ≥1s(防高频 cut 灌入)", () => {
|
||||
// NaN:非 nullish,绕过 ?? 默认值——须回落 15s 语义(16s 恰一条 [0,15s] periodic)
|
||||
let t = mkTransport("stay-nan");
|
||||
let ps = new PageSession(t);
|
||||
startStayTracking(t, ps, { stayIntervalMs: NaN });
|
||||
advance(16_000);
|
||||
t.flush();
|
||||
let stays = staysOf(fetchedEvents("stay-nan"));
|
||||
expect(stays).toHaveLength(1);
|
||||
expect(stays[0].properties.active_ms).toBe(15_000);
|
||||
expect(stays[0].properties.flush_reason).toBe("periodic");
|
||||
|
||||
// 0:无守卫时 setInterval(0) 每毫秒 cut 灌入事件;钳到下限后 5s 内切分有界。
|
||||
// 首秒 tick/cut 同瞬触发顺序不定——断言保持顺序无关:条数有界、区间 ≥1s、相邻不重叠
|
||||
t = mkTransport("stay-zero");
|
||||
ps = new PageSession(t);
|
||||
startStayTracking(t, ps, { stayIntervalMs: 0 });
|
||||
advance(5_000);
|
||||
t.flush();
|
||||
stays = staysOf(fetchedEvents("stay-zero")).sort(
|
||||
(a, b) => a.properties.active_from - b.properties.active_from
|
||||
);
|
||||
expect(stays.length).toBeGreaterThanOrEqual(1);
|
||||
expect(stays.length).toBeLessThanOrEqual(5); // 下限 1s 一刀 → 至多 5 条
|
||||
for (const s of stays) expect(s.properties.active_ms).toBeGreaterThanOrEqual(1_000);
|
||||
for (let i = 1; i < stays.length; i++) {
|
||||
expect(stays[i].properties.active_from).toBeGreaterThanOrEqual(stays[i - 1].properties.active_to); // lastCutEnd 钳制不重叠
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user