JavaScript中async/await结合对话框的Promise失效问题求助
问题排查与解决方案
你的代码中对话框能正常显示,但点击按钮后Promise不生效、对话框无法关闭,主要有以下几个问题和对应的修复方案:
问题1:事件监听器重复绑定且未设置单次触发
每次调用showNameDialogBox时,都会给nameAddButton和nameSkipButton新增点击监听器,多次调用后会导致重复绑定,引发逻辑混乱;且默认监听器会一直存在,即便Promise已经resolve。
修复方案
给addEventListener添加{ once: true }参数,让监听器仅执行一次,执行后自动移除:
document.getElementById("nameAddButton").addEventListener("click", function () { addNameToBase() resolve("Added") }, { once: true }) // 添加once选项 document.getElementById("nameSkipButton").addEventListener("click", function () { resolve("Skipped") }, { once: true })
问题2:addNameToBase()执行出错导致resolve未触发
如果addNameToBase()内部抛出错误,会中断点击事件的代码执行,导致resolve("Added")无法调用,Promise一直处于pending状态,对话框永远不会关闭。
修复方案
给addNameToBase()添加错误捕获,确保无论是否出错都能完成Promise:
document.getElementById("nameAddButton").addEventListener("click", function () { try { addNameToBase() resolve("Added") } catch (err) { console.error("添加名称失败:", err) reject(err) // 也可根据需求resolve一个错误状态 } }, { once: true })
同时在调用showNameDialogBox的地方添加错误捕获,避免未处理的Promise rejection:
(async function () { try { await showNameDialogBox("Zorro", "Cavalier nommé Zorro", "Male", "California, United States"); let nameSelected = document.getElementById("name").value.toLowerCase(); nameSelected = nameSelected.charAt(0).toUpperCase() + nameSelected.slice(1); console.log(nameSelected); } catch (err) { console.error("对话框操作出错:", err) nameManagementDialog.close() // 出错时强制关闭对话框 } })()
问题3:未处理对话框的默认关闭行为
如果用户通过点击对话框外部、按ESC键等默认方式关闭对话框,Promise会一直处于pending状态,nameManagementDialog.close()也不会执行(因为它在await之后)。
修复方案
给对话框添加close事件监听器,在对话框关闭时resolve Promise:
await new Promise(function (resolve, reject) { // 按钮点击监听器... // 处理对话框默认关闭 const handleDialogClose = () => { resolve("Dialog closed") nameManagementDialog.removeEventListener("close", handleDialogClose) } nameManagementDialog.addEventListener("close", handleDialogClose) })
完整修复后的代码示例
const showNameDialogBox = async (firstName, fullname, gender, country) => { initNameDialog(firstName, fullname, gender, country) nameManagementDialog.showModal() await new Promise(function (resolve, reject) { // 定义监听器函数,方便后续移除 const handleAddClick = () => { try { addNameToBase() resolve("Added") } catch (err) { console.error("添加名称失败:", err) reject(err) } } const handleSkipClick = () => { resolve("Skipped") } const handleDialogClose = () => { resolve("Dialog closed") // 移除所有监听器,避免内存泄漏 nameAddButton.removeEventListener("click", handleAddClick) nameSkipButton.removeEventListener("click", handleSkipClick) nameManagementDialog.removeEventListener("close", handleDialogClose) } const nameAddButton = document.getElementById("nameAddButton") const nameSkipButton = document.getElementById("nameSkipButton") nameAddButton.addEventListener("click", handleAddClick, { once: true }) nameSkipButton.addEventListener("click", handleSkipClick, { once: true }) nameManagementDialog.addEventListener("close", handleDialogClose) }) nameManagementDialog.close() } console.log("Before showNameDialog"); (async function () { try { await showNameDialogBox("Zorro", "Cavalier nommé Zorro", "Male", "California, United States"); let nameSelected = document.getElementById("name").value.toLowerCase(); nameSelected = nameSelected.charAt(0).toUpperCase() + nameSelected.slice(1); console.log(nameSelected); } catch (err) { console.error("对话框操作出错:", err) nameManagementDialog.close() } })() console.log("After showNameDialog");
内容的提问来源于stack exchange,提问作者user8889350
相关产品推荐
相关产品推荐

