先追這段程式
建立本地 EventTarget,不需網頁節點。once 監聽器在回呼內立即再觸發 sample;最外層 dispatch 返回前會計到多少?
const target=new EventTarget();let count=0;
target.addEventListener('sample',()=>{count++;target.dispatchEvent(new Event('sample'));},{once:true});
target.dispatchEvent(new Event('sample'));
console.log(count);
1| 觸發位置 | 監聽器是否仍在 | 次數 |
|---|---|---|
| 外層回呼前 | 已移除 | 0 |
| 外層回呼內 | 內層觸發時已不存在 | 1 |
| 外層觸發完成 | 不存在 | 1 |
結果為何如此
once 監聽器在呼叫回呼前已移除,內層同步觸發便找不到它。這只處理當次註冊的監聽器,不會代替持久去重,也不阻止其他或新註冊監聽器。
比較另一種寫法
等回呼尾段才移除,來不及擋住內層觸發。反例最多只呼叫兩次;執行時必須保留次數上限。
const target=new EventTarget();let count=0;
function listener(){count++;if(count<2)target.dispatchEvent(new Event('sample'));target.removeEventListener('sample',listener);}
target.addEventListener('sample',listener);target.dispatchEvent(new Event('sample'));
console.log(count);
2試清邊界
完成後再觸發一次,原 once 監聽器會否再跑?
查看參考答案
不會,它已移除。但重新註冊的 once 監聽器,可在之後觸發時執行。
const target=new EventTarget();let count=0;const listener=()=>count++;
target.addEventListener('sample',listener,{once:true});target.dispatchEvent(new Event('sample'));target.dispatchEvent(new Event('sample'));
target.addEventListener('sample',listener,{once:true});target.dispatchEvent(new Event('sample'));
console.log(count);
2