为什么浏览器在执行JavaScript之前并不总是完成前面HTML的渲染?

Maa*_*ins 7 html javascript browser performance rendering

问题是关于以下代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Test</title>
</head>
<body>
    One line of HTML code
    <script>
        // Synchronous delay of 5 seconds
        var timeWhile = new Date().getTime();
        while( new Date().getTime() - timeWhile < 5000 );
    </script>
</body>
Run Code Online (Sandbox Code Playgroud)

我在Firefox和Chrome中对它进行了测试,它们在5秒后显示(渲染):"一行HTML代码",而不是在5秒内.为什么浏览器会这样做?

我理解为什么浏览器在执行JavaScript时必须停止渲染,因为你可以用JavaScript改变元素的样式(作为例子).如果浏览器必须在同一时刻完全显示和更改内容,则会出现问题.这就是浏览器在执行JavaScript时阻止渲染的原因.

在上面的示例中,当从执行JavaScript开始时,"HTML解析器"已经解析了"一行HTML代码".它必须,因为JavaScript可以包含例如document.write,所以附加的字符串必须在前面的HTML之后.显然,在"解析HTML"和显示/呈现相同的HTML之间有一段时间,因为否则此示例中的浏览器已经在5秒内显示了某些内容,但事实并非如此.

当您用大量HTML代码替换"一行HTML代码"时,浏览器将在5秒内显示一些内容,因此原则上可以显示一些内容.

如果我是一个浏览器,那么我会这样做:

  • 解析"一行HTML代码"
  • 看到一些JavaScript块
  • 完成在"JavaScript块"之前呈现HTML,以便浏览器在此时显示:"一行HTML代码"
  • 现在暂停渲染并执行JavaScript代码.
  • 执行JavaScript代码后,再次开始渲染.

在这样的示例中,浏览器可以在5秒前显示一些内容.这在渲染方面是一个很大的速度提升.

也许这是浏览器可以改进的东西,但也许还有其他原因.也许有人知道更多,并可以解释我.

seg*_*ult 0

解析和渲染是两个不同的操作,可以由浏览器独立运行,但两者都可以对 HTML/CSS/等代码的小片段进行操作,并且不需要完全加载所有资源来开始执行各自的工作。当然,渲染的任何内容都必须首先进行解析,但似乎解析不一定需要完全完成才能运行 JavaScript 代码,并且为了尽快开始向用户显示内容,这对于浏览器在解析完成之前开始渲染页面。

考虑对示例代码进行此修改(我在 macOS 上的 Google Chrome 版本 62.0.3202.75 中对此进行了测试):

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Test</title>
    </head>
    <body>
        One line of html code
        <script>
            // Synchronous delay of 5 seconds
            var timeWhile = new Date().getTime();
            for (var current = new Date().getTime(); current - timeWhile < 5000; current = new Date().getTime()) {
                if (current - timeWhile === 2500) {
                    alert(document.body.childNodes[0].nodeValue);
                    alert(document.body.childNodes[2].nodeValue);
                }
            };
        </script>
        Another line of HTML code
    </body>
Run Code Online (Sandbox Code Playgroud)

alert()在代码中添加了 s 而不是console.log()s,因为刷新/写入 JavaScript 控制台似乎也被同步延迟阻止。

第一个alert()在页面上出现任何文本之前显示“一行 html 代码”字符串,证明页面的该部分在呈现之前已被解析。

然而,第二个alert()并没有发生。由于“另一行 HTML 代码”行尚未解析,因此它未定义为 的子节点document.body,因此尝试访问它会引发错误,导致警报无法显示,而是显示在 JavaScript 控制台中Uncaught TypeError: Cannot read property 'nodeValue' of undefined: 。

如果您在页面加载后在控制台中手动重新运行alert(document.body.childNodes[2].nodeValue);,您会如预期看到一条带有“另一行 HTML 代码”的警报。

我不确定为什么“一行 html 代码”字符串在同步延迟发生之前没有呈现在页面上,但我假设该行为特定于浏览器的实现。