You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何我的async函数未正常工作?JS弹窗事件绑定异常排查

问题原因
  • alretMaker 虽标记为 async 函数,但内部依赖的 setInterval 是异步定时器,且函数本身没有返回可等待的Promise。await alretMaker() 会直接跳过等待,立刻执行后续的 spanMaker——此时弹窗还未全部生成,document.querySelectorAll('span') 无法获取到所有关闭按钮,导致事件绑定失效。
  • 手动执行 spanMaker 时,弹窗已全部生成,自然能获取到完整的span元素集合,事件绑定正常生效。
修复方案

修改 alretMaker,让它返回一个Promise,在所有弹窗生成完成(定时器被清除时)resolve这个Promise,同时优化变量作用域避免全局污染:

let thoughts = ['1', '2', '3', '4', '5']

// 修正拼写:alret → alert(建议规范命名)
const alertMaker = async () => {
    return new Promise((resolve) => {
        let i = 0; // 将i放在函数内部,避免全局变量冲突
        const interval = setInterval(() => {
            const div = document.createElement('div')
            const alert = document.createElement('span')
            document.body.append(div)
            div.append(alert)
            div.className = 'alert primary'
            alert.className = 'close'
            alert.innerText = '×'
            div.append(thoughts[i])
            i++;
            if (i >= thoughts.length) {
                clearInterval(interval)
                resolve() // 所有弹窗生成完毕,通知Promise完成
            }
        }, 1000)
    })
}

const spanMaker = () => { // 无异步操作,无需标记async
    const spans = document.querySelectorAll('span.close') // 精准选择关闭按钮
    for (let span of spans) {
        span.addEventListener('click', () => {
            span.parentElement.style.display = 'none'
        })
    }
}

const runCode = async () => {
    await alertMaker()
    spanMaker() // 同步函数无需await
}
runCode()
更优方案:事件委托

无需等待弹窗生成,直接用事件委托绑定一次事件即可处理所有现有和未来的关闭按钮:

let thoughts = ['1', '2', '3', '4', '5']

const alertMaker = async () => {
    return new Promise((resolve) => {
        let i = 0;
        const interval = setInterval(() => {
            const div = document.createElement('div')
            const alert = document.createElement('span')
            document.body.append(div)
            div.append(alert)
            div.className = 'alert primary'
            alert.className = 'close'
            alert.innerText = '×'
            div.append(thoughts[i])
            i++;
            if (i >= thoughts.length) {
                clearInterval(interval)
                resolve()
            }
        }, 1000)
    })
}

// 事件委托:监听document点击,判断目标是否为关闭按钮
document.addEventListener('click', (e) => {
    if (e.target.classList.contains('close')) {
        e.target.parentElement.style.display = 'none'
    }
})

const runCode = async () => {
    await alertMaker()
}
runCode()

这种方式无需单独执行spanMaker,性能更优,也避免了元素生成时机的问题。

内容的提问来源于stack exchange,提问作者Murtaza Alkabie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:06:28