浏览器debugger为什么没有阻止浏览器渲染界面而alert可以?

看代码

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<div id="text">你好</div>
  <button id="update">更新</button>
  <script>
  update.onclick=function(){
    text.innerHTML='hello'
    alert()
  }
  </script>
</body>
</html>

在线调试jsbin

上面的代码当我点击按钮时弹出了alert()但是界面没有变化,知道alert执行完才看到变化
但是用debugger却不可以,这是为什么?我想知道debugger的原理是什么?

阅读 5.8k
4 个回答

感谢各位的回答,应该解答了我的这个疑惑还有另个跟promsie相关的疑惑,我现在感觉可以这么理解来解释了。

加断点跟不加断点的区别:根绝 @xdsnet 的说法,
加断点时:浏览器是一次扔给js执行线程一行代码,执行完这行代码后执行栈已经没有其他代码了,读取不到了,浏览器任务此时代码执行完毕了,所以就开始GUI render,此时可以看到界面发生变化.

不加断点时:浏览器执行完一行代码会继续读取另一行代码,直到没有可执行的代码为止包括也没有微任务队列了然后开始GUI render,由于是瞬间的给我们的感觉是同时的.
可以看这个代码

 <script>
setTimeout(()=>{
  Promise.resolve().then(()=>{
   text.innerHTML="改变后的"
    console.log('123')
  })
  console.log('没有改变呢')
},1000)
  </script>

clipboard.png
从图中可以看到GUI render的事件确实是晚于所有代码的执行时间,这也解释了我的另外一个疑惑:为什么断点调试时promsie微任务队列里面的回调的代码没有执行完时就看到了界面变化,这其实还是因为debugger是一点点扔代码给浏览器的原因。

现在我的疑惑大致解决了,但也可能理解的不对。希望指出

alert执行完才看到变化

我觉得原因在于 执行到alert语句时直接阻塞了浏览器的GUI渲染线程,alert前加一句console.log,可以发现这时候值是变化了的,但GUI渲染是被阻塞了的,所以界面没有变化。

  update.onclick = function() {
    text.innerHTML = 'hello'
    console.log(text.innerHTML)  // 能打印出 hello
    alert()
  }

debugger语句只是暂停JS的执行,并不会影响到浏览器的渲染。

alert是浏览器调用模态窗口,javascript又是单程执行的,模态窗口不退出时不会执行后续语句的,所以程序被阻塞了。
而debugger其实仅仅是触发浏览器插件工具进行执行控制,和本身javascript运行其上不在一个执行过程中了(它一点一点的喂信息给执行程序的),所以不会阻塞,而是暂停程序。不过如果喂一个alert进去,其实还会阻塞。

理解错了,可以不用看了。
看楼上回答吧。
innerHTML操作不会放入任务队列,直接在执行栈中执行,实际是先执行innerHTML,再执行alert
以下为原错误答案:


正常情况下,执行这个点击事件时,会将text.innerHTML='hello'放入任务队列,alert放入执行栈,所以alert优先执行。

逐步调试或者加断点的时候,执行到text.innerHTML='hello'时或者在它之后加断点,之后的内容不会被加入到执行栈中。执行栈中只有text.innerHTML='hello'

也就是说,逐步调试其实是把当前步加入到执行栈;断点就是检测断点之前的代码分别放入任务队列和执行栈,断点之后的代码不进行检测。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏