如何模拟addEventListener同步触发未捕获错误且不中断后续回调
背景
当执行通过addEventListener添加的回调时,浏览器会按顺序执行回调。若其中一个回调执行失败,会同步触发未捕获错误,但不会中断或阻止后续处理器的执行。
例如执行以下代码:
let button = document.createElement("button"); button.textContent = 'Click'; document.body.append(button); button.addEventListener('click', () => { console.log('1st listener'); throw new Error('error'); }); button.addEventListener('click', () => { console.log('2nd listener'); }); console.log("Before click"); button.click(); console.log("After click");
会输出如下日志:
Before click 1st listener Uncaught Error: error 2nd listener After click
关键在于错误发生在两个监听器执行之间,但后续监听器仍会正常执行。
问题
我希望在自定义的类addEventListener框架中模拟这一行为(若能直接继承EventTarget就不会有此需求了)。以下示例代码展示了我的目标:
let callbacks = [ () => { console.log('1st listener'); throw new Error("error"); }, () => { console.log('2nd listener') }, ]; function triggerHandlers() { for(let cb of callbacks) { try { cb(); } catch(e) { console.error(e); // 如何在此同步触发未捕获错误且不中断for循环? } } } console.log("Before click"); triggerHandlers(); console.log("After click");
可行方案思路
- 或许可以使用
finally块结合递归调用替代for循环?不过这种写法不太规范,我更希望有更直接的非递归方案。 - 使用内置的
EventTarget规避问题,但这对我来说并非可行方案,除非是在代码库中“针对性”模拟上述行为的不规范用法(即不按其预期用途使用)。
不可行方案
- 通过
setTimeout(()=>throw e, 0)(或类似异步方式)重新抛出错误不可行,因为这不是同步操作。
内容的提问来源于stack exchange,提问作者joe
相关产品推荐
相关产品推荐

