自定义模态框通过dispatchEvent触发时如何实现await等待?
解决dispatchEvent触发事件后等待Promise完成的问题
原代码的核心问题
- 按钮点击事件返回的Promise从未被resolve:关闭按钮的点击事件仅返回
true,未调用Promise的resolve方法,导致Promise一直处于pending状态。 dispatchEvent()本身不返回事件处理函数的返回值:它返回的是布尔值(表示事件是否被阻止默认行为),因此await btn.dispatchEvent(event)无法实现等待模态框关闭的效果。
修复方案
将模态框的显示/等待关闭逻辑封装为独立异步函数,让按钮点击事件调用该函数,同时确保触发事件后能获取到对应的Promise进行等待。
完整代码示例
<button id="myBtn">Open Modal and wait (Note: this should't be red before closing modal)</button> <div id="myModal" class="modal"> <div class="modal-content"> <span class="close">×</span> <p>Some text in the Modal..</p> </div> </div> <style> .modal { display: none; position: fixed; z-index: 1; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgb(0,0,0); background-color: rgba(0,0,0,0.4); } .modal-content { background-color: #fefefe; margin: 15% auto; padding: 20px; border: 1px solid #888; width: 80%; } .close { color: #aaa; float: right; font-size: 28px; font-weight: bold; } .close:hover, .close:focus { color: black; text-decoration: none; cursor: pointer; } </style> <script> const modal = document.getElementById("myModal"); const btn = document.getElementById("myBtn"); const span = document.getElementsByClassName("close")[0]; // 封装模态框异步逻辑:显示并等待关闭 async function openModalAndWait() { modal.style.display = "block"; return new Promise(resolve => { // 绑定单次触发的关闭事件,避免重复绑定 const handleClose = () => { modal.style.display = "none"; span.removeEventListener("click", handleClose); resolve(); // 关闭时resolve Promise }; span.addEventListener("click", handleClose); }); } // 按钮点击事件关联封装函数 btn.addEventListener("click", openModalAndWait); (async () => { btn.style.color = "black"; // 直接调用封装函数实现等待,替代dispatchEvent的无效await await openModalAndWait(); btn.style.color = "red"; })(); </script>
关键改进点
- 独立封装异步逻辑:
openModalAndWait()统一处理模态框显示和关闭后的Promise resolve,逻辑更清晰可复用。 - 避免事件重复绑定:使用
addEventListener绑定关闭事件,触发后立即移除,防止多次点击按钮导致事件叠加。 - 直接等待封装函数:由于
dispatchEvent无法返回事件处理函数的Promise,直接调用封装函数是最简洁的等待方式。
可选:通过自定义事件传递Promise
如果必须通过dispatchEvent触发并获取Promise,可借助自定义事件传递:
// 修改按钮点击事件 btn.addEventListener("click", async (e) => { const modalPromise = openModalAndWait(); // 将Promise挂载到事件对象上 e.modalPromise = modalPromise; await modalPromise; }); (async () => { btn.style.color = "black"; const event = new Event('click'); btn.dispatchEvent(event); // 等待事件对象上的Promise await event.modalPromise; btn.style.color = "red"; })();
内容的提问来源于stack exchange,提问作者Dejan Dozet
相关产品推荐
相关产品推荐

