如何获取按键释放的准确时机?JS的keyup事件精度不足
Hey there, I’ve run into this exact head-scratcher before—totally confusing when you first notice that your keyup timestamp never seems to be more than 500ms or so after keydown, even if you held the key for 10 seconds! Let’s break down what’s going on and how to fix it.
Why This Happens
The issue boils down to how browsers handle repeated key presses: when you hold a key down, the browser doesn’t just fire one keydown event—it fires a sequence of them. The first keydown happens when you press the key, then after a short delay (usually ~500ms, matching your system’s key repeat settings), it starts firing repeated keydown events at a faster interval.
When you finally release the key, the keyup event only associates itself with the last repeated keydown event, not the initial one. That’s why the time difference between keyup and that last keydown is only a few hundred ms max—even if you held the key for ages.
The Solution: Track the Initial Keydown Time
To get the actual duration the key was held, you need to ignore the repeated keydown events and only record the timestamp of the first one. Here’s a simple implementation:
// Track if the key is already held down let isKeyActive = false; let initialPressTime; document.addEventListener('keydown', (event) => { // Only record the first keydown, not repeats if (!isKeyActive) { isKeyActive = true; initialPressTime = event.timeStamp; console.log('First keydown at:', initialPressTime); } }); document.addEventListener('keyup', (event) => { if (isKeyActive) { isKeyActive = false; const releaseTime = event.timeStamp; const actualHoldDuration = releaseTime - initialPressTime; console.log('Actual hold duration:', actualHoldDuration + 'ms'); } });
Handling Multiple Simultaneous Keys
If your app needs to support holding multiple keys at once, you’ll want to track each key’s state individually using an object instead of a single boolean:
// Track state for each unique key const keyTracker = {}; document.addEventListener('keydown', (event) => { const keyCode = event.code; // Use code for consistent key identification if (!keyTracker[keyCode]) { keyTracker[keyCode] = { isHeld: true, startTime: event.timeStamp }; console.log(`Key ${keyCode} pressed at:`, keyTracker[keyCode].startTime); } }); document.addEventListener('keyup', (event) => { const keyCode = event.code; if (keyTracker[keyCode]?.isHeld) { const holdDuration = event.timeStamp - keyTracker[keyCode].startTime; console.log(`Key ${keyCode} held for:`, holdDuration + 'ms'); // Clean up the tracker entry delete keyTracker[keyCode]; } });
Quick Notes
- For even more precise timing, you can replace
event.timeStampwithperformance.now()—both are relative timestamps, butperformance.now()often has slightly higher precision in some browsers. - Different operating systems and browsers might have slightly different key repeat delays, but this logic works consistently across all major platforms.
内容的提问来源于stack exchange,提问作者OMGsh

