Skip to content

Commit 578690d

Browse files
committed
extract IdleWrapper
1 parent a3c1475 commit 578690d

File tree

8 files changed

+264
-214
lines changed

8 files changed

+264
-214
lines changed

src/api/const.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,6 @@ export const requestAnimationFrame =
1919
/*@__PURE__*/ window.requestAnimationFrame.bind(window);
2020
export const cancelAnimationFrame =
2121
/*@__PURE__*/ window.cancelAnimationFrame.bind(window);
22-
export const requestIdleCallback =
23-
/*@__PURE__*/ window.requestIdleCallback.bind(window);
24-
export const cancelIdleCallback =
25-
/*@__PURE__*/ window.cancelIdleCallback.bind(window);
26-
// https://rollupjs.org/troubleshooting/#avoiding-eval
27-
export const lesserEval = /*@__PURE__*/ window.eval.bind(window);
2822

2923
export const TAG_MISSFORTUNE = '❓\u00A0⟪N/A⟫';
3024
export const TAG_EVAL_RETURN_SET_TIMEOUT = '(N/A - via setTimeout)';

src/api/settings.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import type {
2-
TCancelAnimationFrameHistory,
32
TCancelIdleCallbackHistory,
3+
TRequestIdleCallbackHistory,
4+
} from '../wrapper/IdleWrapper.ts';
5+
import type {
6+
TCancelAnimationFrameHistory,
47
TClearTimerHistory,
58
TRequestAnimationFrameHistory,
6-
TRequestIdleCallbackHistory,
79
TSetTimerHistory,
810
} from '../wrapper/Wrapper.ts';
911

src/view/components/EvalMetrics.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script lang="ts">
2-
import type { TEvalHistory } from '../../wrapper/ApiEval.ts';
2+
import type { TEvalHistory } from '../../wrapper/EvalWrapper.ts';
33
import Variable from './Variable.svelte';
44
import Trace from './Trace.svelte';
55
import TraceDomain from './TraceDomain.svelte';

src/view/components/IdleCallbackCancelHistory.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script lang="ts">
2-
import type { TCancelIdleCallbackHistory } from '../../wrapper/Wrapper.ts';
2+
import type { TCancelIdleCallbackHistory } from '../../wrapper/IdleWrapper.ts';
33
import {
44
getSettings,
55
setSettings,

src/view/components/IdleCallbackRequestHistory.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<script lang="ts">
22
import type {
3-
TRequestIdleCallbackHistory,
43
TCancelIdleCallbackHistory,
5-
} from '../../wrapper/Wrapper.ts';
4+
TRequestIdleCallbackHistory,
5+
} from '../../wrapper/IdleWrapper.ts';
66
import {
77
DEFAULT_SORT_RIC,
88
getSettings,

src/wrapper/ApiEval.ts renamed to src/wrapper/EvalWrapper.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { lesserEval } from '../api/const.ts';
21
import { cloneObjectSafely } from '../api/clone.ts';
32
import {
43
TraceUtil,
@@ -19,7 +18,10 @@ export type TEvalHistory = {
1918
selfTime: number | null;
2019
};
2120

22-
export class ApiEval {
21+
// https://rollupjs.org/troubleshooting/#avoiding-eval
22+
const lesserEval = /*@__PURE__*/ window.eval.bind(window);
23+
24+
export class EvalWrapper {
2325
traceUtil: TraceUtil;
2426
evalHistory: Map</*traceId*/ string, TEvalHistory> = new Map();
2527
callCounter = 0;
@@ -59,7 +61,7 @@ export class ApiEval {
5961
}
6062

6163
wrap() {
62-
window.eval = function WrappedLessEval(this: ApiEval, code: string) {
64+
window.eval = function WrappedLessEval(this: EvalWrapper, code: string) {
6365
const err = new Error(TraceUtil.SIGNATURE);
6466
const callstack = this.traceUtil.createCallstack(err, code);
6567
let rv: unknown;

src/wrapper/IdleWrapper.ts

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
import type { TPanelVisibilityMap } from '../api/settings.ts';
2+
import { TAG_EXCEPTION } from '../api/clone.ts';
3+
import { trim2microsecond } from '../api/time.ts';
4+
import {
5+
TraceUtil,
6+
type ETraceDomain,
7+
type TCallstack,
8+
type TTrace,
9+
} from './TraceUtil.ts';
10+
import { validHandler, validTimerDelay } from './util.ts';
11+
12+
export type TRequestIdleCallbackHistory = {
13+
traceId: string;
14+
trace: TTrace[];
15+
traceDomain: ETraceDomain;
16+
calls: number;
17+
handler: number | undefined | string;
18+
delay: number | undefined | string;
19+
didTimeout: undefined | boolean;
20+
online: number;
21+
canceledCounter: number;
22+
canceledByTraceIds: string[] | null;
23+
selfTime: number | null;
24+
};
25+
export type TCancelIdleCallbackHistory = {
26+
traceId: string;
27+
trace: TTrace[];
28+
traceDomain: ETraceDomain;
29+
calls: number;
30+
handler: number | undefined | string;
31+
};
32+
33+
const requestIdleCallback = window.requestIdleCallback.bind(window);
34+
const cancelIdleCallback = window.cancelIdleCallback.bind(window);
35+
36+
export class IdleWrapper {
37+
traceUtil: TraceUtil;
38+
onlineIdleCallbackLookup: Map</*handler*/ number, /*traceId*/ string> =
39+
new Map();
40+
ricHistory: Map</*traceId*/ string, TRequestIdleCallbackHistory> = new Map();
41+
cicHistory: Map</*traceId*/ string, TCancelIdleCallbackHistory> = new Map();
42+
callCounter = {
43+
requestIdleCallback: 0,
44+
cancelIdleCallback: 0,
45+
};
46+
native = {
47+
requestIdleCallback: requestIdleCallback,
48+
cancelIdleCallback: cancelIdleCallback,
49+
};
50+
51+
constructor(traceUtil: TraceUtil) {
52+
this.traceUtil = traceUtil;
53+
}
54+
55+
ricFired(
56+
handler: number,
57+
traceId: string,
58+
deadline: IdleDeadline,
59+
selfTime: number | null
60+
) {
61+
const ricRecord = this.ricHistory.get(traceId);
62+
if (!ricRecord) {
63+
return;
64+
}
65+
66+
ricRecord.didTimeout = deadline.didTimeout;
67+
ricRecord.selfTime = trim2microsecond(selfTime);
68+
69+
if (this.onlineIdleCallbackLookup.get(handler)) {
70+
this.onlineIdleCallbackLookup.delete(handler);
71+
ricRecord.online--;
72+
}
73+
}
74+
75+
updateRicHistory(
76+
handler: number,
77+
delay: number | undefined | string,
78+
callstack: TCallstack
79+
) {
80+
const existing = this.ricHistory.get(callstack.traceId);
81+
const hasError = !validTimerDelay(delay);
82+
delay = hasError ? TAG_EXCEPTION(delay) : trim2microsecond(delay);
83+
84+
if (existing) {
85+
existing.calls++;
86+
existing.handler = handler;
87+
existing.didTimeout = undefined;
88+
existing.delay = delay;
89+
existing.online++;
90+
} else {
91+
this.ricHistory.set(callstack.traceId, {
92+
traceId: callstack.traceId,
93+
trace: callstack.trace,
94+
traceDomain: this.traceUtil.getTraceDomain(callstack.trace[0]),
95+
calls: 1,
96+
handler,
97+
didTimeout: undefined,
98+
delay,
99+
online: 1,
100+
canceledCounter: 0,
101+
canceledByTraceIds: null,
102+
selfTime: null,
103+
});
104+
}
105+
106+
this.onlineIdleCallbackLookup.set(handler, callstack.traceId);
107+
}
108+
109+
updateCicHistory(handler: number | string, callstack: TCallstack) {
110+
const existing = this.cicHistory.get(callstack.traceId);
111+
const hasError = !validHandler(handler);
112+
113+
if (hasError) {
114+
handler = TAG_EXCEPTION(handler);
115+
}
116+
117+
if (existing) {
118+
existing.calls++;
119+
existing.handler = handler;
120+
} else {
121+
this.cicHistory.set(callstack.traceId, {
122+
traceId: callstack.traceId,
123+
trace: callstack.trace,
124+
traceDomain: this.traceUtil.getTraceDomain(callstack.trace[0]),
125+
calls: 1,
126+
handler,
127+
});
128+
}
129+
130+
const ricTraceId = this.onlineIdleCallbackLookup.get(Number(handler));
131+
const ricRecord = ricTraceId && this.ricHistory.get(ricTraceId);
132+
if (ricRecord) {
133+
this.onlineIdleCallbackLookup.delete(Number(handler));
134+
135+
ricRecord.online--;
136+
ricRecord.didTimeout = undefined;
137+
138+
if (ricRecord.canceledByTraceIds === null) {
139+
ricRecord.canceledByTraceIds = [callstack.traceId];
140+
} else if (!ricRecord.canceledByTraceIds.includes(callstack.traceId)) {
141+
ricRecord.canceledByTraceIds.push(callstack.traceId);
142+
}
143+
ricRecord.canceledCounter++;
144+
}
145+
}
146+
147+
wrapRequestIdleCallback() {
148+
window.requestIdleCallback = function requestIdleCallback(
149+
this: IdleWrapper,
150+
fn: IdleRequestCallback,
151+
options?: IdleRequestOptions | undefined
152+
) {
153+
const delay = options?.timeout;
154+
const err = new Error(TraceUtil.SIGNATURE);
155+
const callstack = this.traceUtil.createCallstack(err, fn);
156+
157+
this.callCounter.requestIdleCallback++;
158+
const handler = this.native.requestIdleCallback((deadline) => {
159+
const start = performance.now();
160+
let selfTime = null;
161+
162+
if (this.traceUtil.shouldPass(callstack.traceId)) {
163+
if (this.traceUtil.shouldPause(callstack.traceId)) {
164+
debugger;
165+
}
166+
fn(deadline);
167+
selfTime = performance.now() - start;
168+
}
169+
170+
this.ricFired(handler, callstack.traceId, deadline, selfTime);
171+
}, options);
172+
this.updateRicHistory(handler, delay, callstack);
173+
174+
return handler;
175+
}.bind(this);
176+
}
177+
178+
wrapCancelIdleCallback() {
179+
window.cancelIdleCallback = function cancelIdleCallback(
180+
this: IdleWrapper,
181+
handler: number
182+
) {
183+
const err = new Error(TraceUtil.SIGNATURE);
184+
const callstack = this.traceUtil.createCallstack(err);
185+
186+
this.updateCicHistory(handler, callstack);
187+
this.callCounter.cancelIdleCallback++;
188+
189+
if (this.traceUtil.shouldPass(callstack.traceId)) {
190+
if (this.traceUtil.shouldPause(callstack.traceId)) {
191+
debugger;
192+
}
193+
this.native.cancelIdleCallback(handler);
194+
}
195+
}.bind(this);
196+
}
197+
198+
unwrapRequestIdleCallback() {
199+
window.requestIdleCallback = this.native.requestIdleCallback;
200+
}
201+
202+
unwrapCancelIdleCallback() {
203+
window.cancelIdleCallback = this.native.cancelIdleCallback;
204+
}
205+
206+
collectHistory(panels: TPanelVisibilityMap) {
207+
return {
208+
ricHistory: panels.requestIdleCallback.visible
209+
? Array.from(this.ricHistory.values())
210+
: null,
211+
cicHistory: panels.cancelIdleCallback.visible
212+
? Array.from(this.cicHistory.values())
213+
: null,
214+
};
215+
}
216+
217+
cleanHistory() {
218+
this.ricHistory.clear();
219+
this.cicHistory.clear();
220+
this.onlineIdleCallbackLookup.clear();
221+
222+
this.callCounter.requestIdleCallback = 0;
223+
this.callCounter.cancelIdleCallback = 0;
224+
}
225+
}

0 commit comments

Comments
 (0)