先看這個固定例子
程式先點一次,再 abort 該監聽器的 controller,然後再點。印出的數字只記這段固定生命週期,不代表其他工作也被取消。
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<button id="action" type="button">計本地點擊</button><output id="result"></output>
<script>let count=0;const controller=new AbortController();const action=document.querySelector('#action');action.addEventListener('click',()=>count++,{signal:controller.signal});action.click();controller.abort();action.click();
const result=count;
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>1| 核對項目 | 所給輸入或動作 | 結果 |
|---|---|---|
| 第一次點擊 | signal 未終止 | count: 1 |
| abort() | signal.aborted | true |
| 第二次點擊 | 監聽器已移除 | count: 1 |
原生機制怎樣處理
signal 選項把該監聽器連到 controller,abort 後便不再接收事件。已 abort 的 signal 不會加入新監聽器;另一個仍有效的 signal 所屬監聽器可照常跑,並非全域暫停。
比較另一寫法
另外設 disposed 旗標,但回呼沒有讀它、也沒有移除,兩次固定點擊仍會累加。
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<button id="action" type="button">計本地點擊</button><output id="result"></output>
<script>let count=0,disposed=false;const action=document.querySelector('#action');action.addEventListener('click',()=>count++);action.click();disposed=true;action.click();
const result={disposed,count};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"disposed":true,"count":2}試清邊界
用已 abort 的 signal 加監聽器,會否執行?另用新的 controller 又如何?
查看參考答案
舊 signal 的監聽器不會跑;新監聽器先跑一次,再 abort 就擋住下一次固定點擊。
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<button id="action" type="button">計本地點擊</button><output id="result"></output>
<script>let oldCount=0,liveCount=0;const old=new AbortController();old.abort();const live=new AbortController();const action=document.querySelector('#action');action.addEventListener('click',()=>oldCount++,{signal:old.signal});action.addEventListener('click',()=>liveCount++,{signal:live.signal});action.click();live.abort();action.click();
const result={oldCount,liveCount,oldAborted:old.signal.aborted,liveAborted:live.signal.aborted};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"oldCount":0,"liveCount":1,"oldAborted":true,"liveAborted":true}