为什么我在比较调试和未附加调试器的 运行 时在此代码中看到不同的输出?

Why do I see different outputs in this code when comparing debugging and running without the debugger attached?

<button id="BTN" type="button">Click Me</button>
<p id="p-text"></p>
<p id="p-result"></p>
<script>
    document.getElementById("BTN").addEventListener('click', function () {
        document.getElementById("p-text").innerText = "Calculating...."    // breakpoint set here
        foo();
        // setTimeout(foo, 0); 
    })
    foo = function () {
        let result = 0;
        for (let i = 0; i < 1000; i++) {
            for (let j = 0; j < 1000; j++) {
                for (let k = 0; k < 1000; k++) {
                    result = result + i + j + k;
                }
            }
        }
        document.getElementById("p-text").innerText = "Calculate Done"
        document.getElementById("p-result").innerText = result.toString()
    }
</script>

我知道当点击上面页面上的按钮时应该将“正在计算...”替换为“计算完成”并将 foo 函数的结果插入到 p-result 标签中!并且上面的页面永远不会显示“正在计算...”导致事件队列的顺序。

问题是:为什么当我在 Chrome 中使用调试器时,它在页面上显示“正在计算...”,而 foo 函数尚未结束?

会显示这个

这是因为debugger关键字或断点只会阻塞JavaScript执行;事件循环实际上不会被完全阻塞。
"pause" part of the event loop which asks the User Agent (UA) to not follow the specs and instead to choose a way to pause the JS execution while keeping the rendering alive, like the enter the "spin the event loop"算法中有一个注释确实如此。各种情况下都会达到这个状态,在spec中都没有定义,都不是标准的(即所有UA都不做)。

定义的一个是延迟脚本are being fetched。一个不标准的是所有用户提示,如 alert(),其中 Firefox 将继续更新呈现,但 Chrome 不会。

debugger 或断点不是 HTML 规范的一部分(它确实指定了事件循环的行为),我不知道是否所有支持它的浏览器的行为都一样,但似乎主要供应商确实如此。

请注意,这里的两个示例都没有真正使用“旋转事件循环”算法,因为它们不会执行 true 算法会执行的微任务检查点。