【问题标题】:Do eventlisteners callback functions go into callback queue?eventlisteners 回调函数是否进入回调队列?
【发布时间】:2022-11-02 10:21:30
【问题描述】:

我认为根据我的理解,回调函数被放置在回调队列中并且在调用堆栈为空之前不会执行,所以在下面的代码中,为什么事件侦听器的回调函数是在console.log(index) 是按钮单击时执行的跑步 ?在调用堆栈中存在的所有函数console.log() 执行后,背景颜色是否应该改变?

<button>Click me</button>

<script>
    for (let index = 0; index < 100000; index++) {
        console.log(index)   
    }

    document.querySelector('button').addEventListener('click',()=>{
        document.querySelector('body').style.backgroundColor = 'red'
    })
</script>

【问题讨论】:

    标签: javascript asynchronous callback synchronization callstack


    【解决方案1】:

    您的代码全部同步。

    上面会发生的是线程将被阻塞,直到 for 循环结束。

    然后您将创建一个箭头函数 - 将捕获全局 ctx - 并保存在内存中

    代码会将这个 fn 的 ref 传递给 addeventlistern,它会将 fn ref 推送到一旦事件发出就被调用的回调列表

    总结是按钮单击将触发bg。

    换句话说,在 for 循环完成之前,您没有事件到达您注册回调的位置,因此它不会触发(但 10k 的 forloop 可能会在不到 10 毫秒内完成),然后您将注册 Cb 并保持良好状态去

    【讨论】:

      【解决方案2】:

      是的,因为for循环是同步的,所以即使是10万的循环,它们都是同时开始运行的,所以剩下的代码也会被执行,甚至在所有控制台log()执行之前. 一个示例来证明这一点,我尝试了一次类似的事情,方法是在 for 循环中放置一个 settimeout 以在每个循环计数之间产生延迟,如下所示

      for (let i=0; i<31; i++){
      setTimeout(()=>console.log(i), 1000)
      }
      console.log('finished')
      

      这应该每 1 秒运行一次 console.log,但实际行为是 30 个循环计数开始一起运行并在 1 秒内与最后一个 console.log() 一起执行。 因此,知道了这一点,我将其修改为

      for (let i=0; i<31; i++){
      setTimeout(()=>console.log(i), 
      1000*(i+1))
      }
      console.log('finished')
      

      现在经过修改后,循环将每 1 秒运行一次,因为我们将每个循环计数的超时时间增加了 1 秒,这证实了循环计数都是同时开始的,但最后一个 console.log('finish')将在循环甚至开始记录之前运行,因为循环是一个同步代码,在下一行代码运行之前不会等待完成。

      我希望这有帮助

      【讨论】:

      • 感谢您的回答,您的示例是正确的。虽然这里的“for”是这种行为的原因,但是当我们查看另一个案例 >console.log('1') 然后 element.click() 然后 console.log('2')< 这里它会打印 1 然后执行事件的回调函数然后打印 2。所以我认为事件的回调函数将在事件触发后立即执行。
      【解决方案3】:

      我看你问错问题了

      事件监听器是否进入回调队列 (实际上我相信它会进入回调队列)不会改变你的代码的行为,

      在所有情况下for 循环必须在甚至将事件侦听器添加到按钮元素本身之前完成(添加侦听器而不是通过单击运行它).

      因此,如果事件监听器添加到按钮,那么 for 循环必须完成它的工作,这就是已经发生的事情。

      但是您看到的行为正在发生,因为 for 循环已完成其工作但浏览器尚未完成记录数字的工作(将它们呈现在屏幕上)。

      我希望现在已经足够清楚了。 为了更好地理解,您可以:

      • 在您的开发工具控制台中启用时间戳。
      • 在您的监听器中添加另一个console.log。
      • 在您的日志中使用 performance.now() 或 Date.now() 以便在一切都在运行时更好地掌握它。
      • 使用 devtools 调试器逐步运行代码。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-01-05
        • 1970-01-01
        • 1970-01-01
        • 2014-01-27
        • 1970-01-01
        • 2020-07-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多