現象:`keydown` 事件持續觸發,`alert` 阻塞主線程導致隊列堆積,彈窗關閉後連續彈出。
`alert` 是同步阻塞 API,瀏覽器在彈窗期間**不處理新事件**,但鍵盤按住不放會產生**重複 keydown**,排隊等待彈窗關閉後依次執行。
let spaceHandled = false;
document.addEventListener('keydown', function(e) {
if (e.code === 'Space') {
if (spaceHandled) return; // 已在處理中,忽略
spaceHandled = true;
alert('不能添加空格');
// 彈窗關閉後釋放鎖(需異步釋放,避免同步代碼仍在執行)
setTimeout(() => spaceHandled = false, 0);
}
});
function debounceAction(key, action, wait = 300) {
let timer = null, running = false;
return function(e) {
if (e.code !== key) return;
if (running) return;
running = true;
action(e);
clearTimeout(timer);
timer = setTimeout(() => running = false, wait);
};
}
// 使用
document.addEventListener('keydown', debounceAction('Space', e => {
alert('不能添加空格');
}, 1000)); // 1秒內不再觸發
`alert`/`confirm`/`prompt` 會阻塞事件循環,體驗極差。推薦:
| 方案 | 優點 | 缺點 |
|---|---|---|
| 標記位鎖 | 零依賴、邏輯簡單 | 需手動管理釋放時機 |
| 防抖封裝 | 可復用、支持配置等待時間 | 略增代碼量 |
| 非阻塞 UI | 體驗最佳、不阻塞主線程 | 需引入組件庫或自寫樣式 |