跳至內容
Astera Technology

事件內再次觸發同一事件,once 仍只跑一次

once 回呼內再觸發同類事件,核對會執行幾次。

下載完整個案資料及參考答案 ↓

先追這段程式

建立本地 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);
確實的 console 輸出
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

原始例子檔案