Skip to content

Instantly share code, notes, and snippets.

@mmocny
Last active February 27, 2026 19:57
Show Gist options
  • Select an option

  • Save mmocny/c2d73317900eac289f397d8e4368baf5 to your computer and use it in GitHub Desktop.

Select an option

Save mmocny/c2d73317900eac289f397d8e4368baf5 to your computer and use it in GitHub Desktop.
Testing pointerdown + pointercancel relative scheduling
function block(ms) {
const end = performance.now() + ms;
while (performance.now() < end);
}
async function makeMainBusy() {
for (let i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i);
block(10);
}, 0);
}
}
const eventsInAnimationFrame = [];
for (let type of ['pointerdown','pointercancel','pointerup']) {
document.addEventListener(type, async event => {
const processingStart = performance.now();
console.log("dispatch: ", type);
eventsInAnimationFrame.push(type);
block(200);
if (type != "pointerdown") return;
makeMainBusy();
await new Promise(resolve => requestAnimationFrame(resolve));
const renderStart = performance.now()
console.log("renderStart delay:", renderStart - processingStart);
// Note: small bug, you should look for pointercancel for this pointer, i.e. cancel comes after
// I once hit a case where old pointercancel got grouped with new pointerdown
const shouldBeInteraction = !eventsInAnimationFrame.includes("pointercancel");
eventsInAnimationFrame.splice(0, eventsInAnimationFrame.length);
console.log("Event:", event.type, "start:", event.timeStamp, "duration", renderStart-event.timeStamp, "id:", shouldBeInteraction);
}, { capture: true });
}
const observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
if (entry.name == "pointerdown") {
console.log("EventTiming:", entry.name, "start:", entry.startTime, "duration:", entry.duration, "id:", entry.interactionId);
}
}
});
observer.observe({ type: 'event', durationThreshold: 0 });
@mmocny
Copy link
Author

mmocny commented Feb 26, 2026

If you test this snippet, then interact with a scrollable page with touch, the console logs will tell if you if the pointerdown event timing was entirely measured before scroll start or not.


Option 1: small hesitation before starting a scroll:

12:01:27.665 VM77:18 dispatch:  pointerdown
12:01:27.865 VM77:25 renderStart delay: 200.40000000037253
12:01:27.865 VM77:31 Event: pointerdown start: 3118.7000000011176 duration 203.40000000037253 id: true
12:01:27.865 VM77:8 0
12:01:27.875 VM77:8 1
12:01:27.885 VM77:8 2
12:01:27.895 VM77:8 3
12:01:27.905 VM77:8 4
12:01:27.915 VM77:8 5
12:01:27.925 VM77:8 6
12:01:27.936 VM77:8 7
12:01:27.946 VM77:8 8
12:01:27.956 VM77:8 9
12:01:28.078 VM77:18 dispatch:  pointercancel
12:01:28.279 VM77:38 EventTiming: pointerdown start: 3118.7000000011176 duration: 200 id: 0

The "Event" logs id: true which is the snippet's way of suggesting this should be an interaction.

You can see pointercancel is dispatched very late, after next paint (renderStart) and after a bunch of tasks.

The final EventTiming.duration is only 200 which matches the "real" jank of pointerdown.


Option 2: rapid swipe to scroll gesture:

12:01:29.732 VM77:18 dispatch:  pointerdown
12:01:29.933 VM77:18 dispatch:  pointercancel
12:01:30.133 VM77:25 renderStart delay: 401
12:01:30.133 VM77:31 Event: pointerdown start: 5184.700000001118 duration 405.19999999925494 id: false
12:01:30.133 VM77:8 0
12:01:30.144 VM77:8 1
12:01:30.154 VM77:8 2
12:01:30.164 VM77:8 3
12:01:30.174 VM77:8 4
12:01:30.184 VM77:8 5
12:01:30.194 VM77:8 6
12:01:30.204 VM77:8 7
12:01:30.214 VM77:8 8
12:01:30.224 VM77:8 9
12:01:30.234 VM77:38 EventTiming: pointerdown start: 5184.700000001118 duration: 408 id: 0

The "Event" logs id: false which is the snippet's way of suggesting this should NOT be an interaction.

You can see pointercancel is dispatched very early, before next paint (renderStart) and before a bunch of tasks.

The final EventTiming.duration is now 408 which is larger than the "real" jank of pointerdown and also not something the user experiences, since scroll has started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment