事件监听器的回调函数是否会进入回调队列?

3

我认为根据我的理解,回调函数被放置在回调队列中,只有在调用堆栈为空时才会执行。因此,在下面的代码中,为什么事件侦听器的回调函数在单击按钮时执行,而 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>
3个回答

0
是的,因为for循环是同步的,所以即使它是10万次循环,它们都会同时开始运行,所以代码的其余部分也将被执行,甚至在所有console log()被执行之前。 为了演示这一点,我曾尝试过类似的事情,通过在for循环中放置一个settimeout来使每个循环计数之间产生延迟,就像这样。
for (let i=0; i<31; i++){
setTimeout(()=>console.log(i), 1000)
}
console.log('finished')

这段代码应该每隔1秒输出一次console.log,但实际行为是30个循环计数同时开始运行,并在最后一个console.log()执行时一起完成。 因此,我进行了修改:

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

现在,在这个修改之后,循环将每秒运行一次,因为我们为每个循环计数增加了1秒的超时时间,这证实了所有循环计数都从同一时间开始,但是最后的console.log('finish')将在循环开始记录之前运行,因为循环是同步代码,不会等待完成才运行下一行代码。
希望这可以帮助到您。

谢谢你的回答,你的例子是正确的。尽管在这里,“for”语句是导致这种行为的原因,但当我们看另一个案例>console.log('1') then element.click() then console.log('2')<时,它会先打印1,然后执行事件的回调函数,再打印2。所以我认为事件的回调函数将在事件被触发时立即执行。 - Aya Othman

0

您的代码全都是同步的。

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

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

代码将传递此fn的引用给addeventlistern,该引用将推送fn引用到回调列表中,以便在事件被触发时调用

总之,是的,按钮单击将触发背景。

换句话说,在for循环完成之前,您甚至没有达到注册回调的位置,因此它不会触发(但10k的for loop可能会在不到~10ms的时间内完成),之后您将注册Cb,并且可以开始了。


0

我看你的问题是不正确的,

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

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

因此,如果事件侦听器已添加到按钮,则for循环必须完成其工作,这已经发生了。

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

我希望现在已经足够清楚了。

  • 在devtools控制台中启用时间戳。
  • 在你的监听器内部添加另一个console.log。
  • 在你的日志中使用performance.now()或Date.now()更好地理解一切何时在运行。
  • 使用devtools调试器逐步运行代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接