浏览器渲染——html页面外联script会阻塞页面渲染吗?

注:测试浏览器为chrome浏览器

我们先来看第一段代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>测试</title>
    </head>
    <body>
        <h1>Hello</h1>
        <script type="text/javascript">
            let i = 1000000000
            while(i>0){
                i-- 
            }
        </script>
        <h1>world</h1>
    </body>
</html>

 我们知道js会阻塞DOM解析和渲染,所以页面肯定会在内联script里的代码执行完成之后,再渲染出来

答案确实是这样

分析:一开始渲染进程的HTML 解析器开始解析DOM,当解析到内联script 脚本标签时,HTML 解析器会暂停解析DOM,此时JavaScript 引擎介入,并执行内联script 标签中的这段脚本,脚本执行完成之后,HTML 解析器恢复解析过程,继续解析DOM,然后进行后续的渲染,最终将页面上同时渲染出 Hello World

 

接下来,我们看第二段代码:

index.js:

var i = 1000000000
while(i>0){
    i--
}

index.html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>测试</title>
    </head>
    <body>
        <h1>Hello</h1>
        <script type="text/javascript" src="index.js"></script>
        <h1>world</h1>
    </body>
</html>

那这段html代码的运行结果是不是和上面一样呢?

刚开始我以为是,后来发现并不是这样的,谷歌浏览器做了一些优化,所以执行结果会有一些变化

分析:当渲染引擎收到字节流之后,会开启一个预解析线程,用来分析 HTML 文件中包含的 JavaScript、CSS 等相关文件,解析到相关文件之后,预解析线程会提前下载这些文件。因为这段html代码里有外联script脚本,所以会丢到预解析线程去下载这个外联js文件,此时HTML 解析器开始解析DOM,当遇到外联script标签时,停止DOM解析,浏览器会渲染一次页面(当前的Hello会被渲染到页面上),然后执行下载完成的js文件,接着继续解析DOM,然后进行后续的渲染,最终将页面上就会渲染出 Hello World

注意:这里是先渲染出Hello ,然后过一会儿(这个期间在执行js),再渲染出World

 

答案:第一段代码和第二段代码的执行最终结果一样,但是渲染顺序不一样。第一段代码先间隔一段时间(执行js),然后Hello World会同时被渲染出来;第二段代码会先渲染出Hello,然后间隔一段时间(执行js),再渲染出World

总结:

  虽然js都会阻塞DOM解析,但是浏览器对于内联script和外联script的渲染过程还是有一点点不同。内联js会阻塞DOM解析和渲染,直到js执行完成后,页面才会被渲染出来。外联js也会阻塞DOM解析和渲染,但是如果在外联script标签之前已经有DOM元素生成,则浏览器会优先渲染一次。我想这是因为浏览器不知道脚本的内容,因而碰到脚本时,只好先渲染页面,确保脚本能获取到最新的DOM元素信息,尽管脚本可能不需要这些信息。

 

 

——个人理解,如有出错,请指正——  

posted @ 2020-06-19 14:49  蛋片鸡  阅读(1757)  评论(0编辑  收藏  举报