更新:
根据一个答案,我尝试了这个,只有在完全执行控制台日志循环后才能显示HTML文档:
@H_502_2@<html lang="en"> <body onload="onLoad()"> <button onclick="clickHandler()">Click me</button> <p id="counter"> no clicks yet </p> <script> var counter = 0; function clickHandler() { counter++; document.getElementById("counter").innerHTML = "number of clicks:" + counter; } function onLoad() { for (i = 0; i < 99999; ++i) { console.log(i); } console.log("ready to react to your clicks"); } </script> </body> </html>解决方法
Why console.log gets executed before DOM model being generated?
我所理解的“在生成DOM模型之前”是“在创建p元素之前”. p元素是在脚本元素运行之前创建的,并且可以从中访问它.如果你在脚本中执行document.getElementById(“counter”),你将得到你的段落.
然后你问:
why does the loop of console.log finish before any HTML element is displayed?
这是一个不同的问题.这里的问题不是解析已经停止(与Simeon Stoykov suggested相反).确实解析停止了,但它没有解释为什么段落没有显示.浏览器可以在脚本执行时显示段落. (实际上,如果你在脚本元素中放置一个断点,Chrome会在断点被击中时显示该段落.)
发生的事情是浏览器正在应用优化.浏览器尽可能地延迟回流(计算页面上元素的位置和几何)以及元素的渲染.目标是减少回流和渲染所花费的总时间.假设您没有将数字转储到控制台的脚本,而是使用一个脚本来更改段落的样式,从而使段落更改位置或大小.一个天真的浏览器可能会这样做:
>立即回流并渲染p#计数器.
>执行脚本,更新样式,使p#计数器的旧位置和大小发生变化.
>重新流动并渲染p#计数器以反映更改.
像FF或Chrome这样的真实浏览器会跳过上面的第一步,只会重排和渲染一次p#计数器而不是两次.
在像你这样的简单例子中,优化并不是很好,但想象一个复杂的页面,其中包含一堆表和一个启动脚本,可以立即用数据,图像,链接等行填充表格.能够减少X的回流次数 – 渲染操作,只需一次回流渲染即可产生巨大的差异.
在您给出的示例中,浏览器知道在脚本执行时用户无法对页面执行任何操作,因此在脚本完成之前,浏览器中没有任何内容可以呈现页面.
此时出现了一个问题:
If the browser is delaying computing element position and size,then why can I do things like
document.getElementById("counter").getBoundingClientRect()
in my script and get coordinates??
浏览器可以尽可能地延迟它.当JavaScript代码查询元素的位置或大小时,就不再可能延迟.浏览器必须在那里进行回流,然后给出答案. (在我上面的讨论中,我已经谈到了重排并一起渲染以简化一点.但是回流并不一定会立即跟随渲染.因此渲染可能仍然会延迟到脚本执行完毕之后.)
如果您的示例意图表示阻止渲染并阻止您的用户获得任何反馈的长计算,那么解决这个问题的方法就是将冗长的工作分解为块:执行大量工作,然后使用setTimeout来安排下一个块,依此类推,直到整个工作完成.例如:
@H_502_2@const p = document.getElementById("counter"); let i = 0; const limit = 100; const chunkSize = 10; function doWork() { for (let thisChunk = 0; thisChunk < chunkSize && i < limit; thisChunk++) { console.log(i++); p.textContent = i; } if (i < limit) { setTimeout(doWork,0); } } doWork();在上面的示例中,执行了10个数字的块,然后setTimeout调度下一个块,脚本将控制权返回给JavaScript事件循环,后者执行所需的任务.这包括响应用户交互,从而将页面呈现给用户.
在某些情况下,将整个工作卸载到WebWorker中可能是有意义的.