Chromium内核浏览器中requestAnimationFrame调用confirm后时间戳异常求助
Hey there! Let's break down this weird Chromium-specific issue you're facing with requestAnimationFrame (RAF) and modal dialogs, then fix it properly.
What's Going On Here?
When you trigger a confirm dialog before starting your RAF animation, Chromium (Chrome/Opera) behaves differently from Firefox/IE11. The problem boils down to:
- The first
timestamppassed to youranimatefunction is actually the time the frame would have run if the dialog hadn't blocked the page. - When you click OK, the second timestamp is the actual current time. Their difference ends up being the full time you spent staring at the confirm dialog, which throws off your animation progress calculation entirely.
Firefox and IE11 handle this smarter—they pass the actual current time as the first timestamp once the dialog closes, so your animation works as expected. This feels like a Chromium bug (and it probably is), but until it's fixed, we can work around it.
The Fix: Use performance.now() Instead of RAF's Timestamp
The solution relies on performance.now(), a high-precision timer that's not affected by page blocking (like modal dialogs). It tracks the actual time elapsed since the page loaded, so it'll give us the correct start time for our animation, no matter how long the confirm dialog was open.
Here's your modified code with the fix:
const cache = { start: null, target: null }; function animate(timestamp) { console.log('RAF timestamp:', timestamp, '| Actual time:', performance.now()); if (cache.start === null) { // Replace RAF's timestamp with performance.now() for our start time cache.start = performance.now(); } // Calculate progress using the actual current time, not RAF's timestamp const progress = performance.now() - cache.start; cache.target.style.left = Math.min(progress / 10, 100) + 'px'; if (progress < 1000) { requestAnimationFrame(animate); } else { cache.target.style.left = '0px'; cache.start = null; } } (function() { const target = document.getElementsByTagName("div")[0]; cache.target = target; const cb = document.getElementsByTagName("input")[0]; const btn = document.getElementsByTagName("button")[0]; btn.addEventListener("click", function() { if (cb.checked) { if (confirm("Just click 'OK' to start the animation, ok?")) { requestAnimationFrame(animate); } } else { requestAnimationFrame(animate); } }); })();
html, body { padding: 0; margin: 0; } div { width: 50px; height: 50px; border: 1px solid black; background-color: yellowgreen; position: absolute; top: 50px; } button { margin-top: 20px; }
<button type="button">Start</button> <label> <input type="checkbox" />use "confirm" </label> <div></div>
Key Changes Explained
- Initializing the start time: Instead of using the first
timestampfrom RAF, we setcache.starttoperformance.now()when the animation first runs. This captures the exact moment the animation starts executing after the dialog closes. - Calculating progress: We use
performance.now()again to get the current time each frame, so the progress is always based on how long the animation has actually been running—ignoring any time spent blocked by the modal dialog.
Extra Notes
- This workaround works across all browsers, not just Chromium, so it's safe to use universally.
- If you want to push for a fix in Chromium, you can file a bug report in their issue tracker (search for existing issues first using keywords like
requestAnimationFrame timestamp modal confirm—it's possible someone else has reported this already).
内容的提问来源于stack exchange,提问作者Andrei V

