HTML文档的加载与页面的首次渲染

HTML文档的加载与页面的首次渲染

当我们输入一个页面地址时,发生了哪些事情呢?

  • 1、浏览器首先下载该地址所对应的 html 页面。
  • 2、浏览器解析 html 页面的 DOM 结构。
  • 3、开启下载线程对文档中的所有资源按优先级排序下载。
  • 4、主线程继续解析文档,到达 head 节点 ,head 里的外部资源无非是外链样式表和外链 js。
    • 发现有外链 css 或者外链 js,如果是外链 js ,则停止解析后续内容,等待该资源下载,下载完后立刻执行。如果是外链 css,继续解析后续内容。
  • 5、解析到 body

    body 里的情况比较多,body 里可能只有 DOM 元素,可能既有 DOM、也有 css、js 等资源,js 资源又有可能异步加载 图片、css、js 等。DOM 结构不同,浏览器的解析机制也不同,我们分开来讨论。

    • 只有 DOM 元素
      • 这种情况比较简单了,DOM 树构建完,页面首次渲染。
    • 有 DOM 元素、外链 js。
      • 当解析到外链 js 的时候,该 js 尚未下载到本地,则 js 之前的 DOM 会被渲染到页面上,同时 js 会阻止后面 DOM 的构建,即后面的 DOM 节点并不会添加到文档的 DOM 树中。所以,js 执行完之前,我们在页面上看不到该 js 后面的 DOM 元素。
    • 有 DOM 元素、外链 css
      • 外链 css 不会影响 css 后面的 DOM 构建,但是会阻碍渲染。简单点说,外链 css 加载完之前,页面还是白屏。
    • 有 DOM 元素、外链 js、外链 css
      • 外链 js 和外链 css 的顺序会影响页面渲染,这点尤为重要。当 body 中 js 之前的外链 css 未加载完之前,页面是不会被渲染的。
      • 当body中 js 之前的 外链 css 加载完之后,js 之前的 DOM 树和 css 合并渲染树,页面渲染出该 js 之前的 DOM 结构。
  • 6、文档解析完毕,页面重新渲染。当页面引用的所有 js 同步代码执行完毕,触发 DOMContentLoaded 事件。
  • 7、html 文档中的图片资源,js 代码中有异步加载的 css、js 、图片资源都加载完毕之后,load 事件触发。

测试代码如下

<body>
  <!-- 白屏 -->
  <div id="div1"></div>
  <!-- 白屏 -->
  <link rel="stylesheet" href="./c1.css" />
  <!-- 白屏 -->
  <link rel="stylesheet" href="./c3.css" />
  <!-- 如果此时 j1.js 尚未下载到本地,则首次渲染,此时的 DOM 树 只有 div1 ,所以页面上只会显示 div1,样式是 c1.css 和 c3.css 的并集。-->
  <!-- 如果此时 j1.js 已经下载到本地,则先执行 j1.js,页面不会渲染,所以此时仍然是白屏。-->
  <!--下面的 js 阻塞了 DOM 树的构建,所以下面的 div2 没有在文档的 DOM 树中。 -->
  <script src="http://test.com:9000/mine/load/case2/j1.js
  "></script>
  <!-- j1.js 执行完毕,继续 DOM 解析,div2 被构建在文档 DOM 树中,此时页面上有了div2 元素,样式仍然是 c1.css 和 c3.css 的并集 -->
  <link rel="stylesheet" href="./c4.css" />
  <!-- c4.css 加载完毕,重新构建render树,样式变成了 c1.css、c3.css 和 c4.css 的并集 -->
  <div id="div2"></div>
  <script>
  // 利用 performance 统计 load 加载时间。
    window.onload=function(){console.log(performance.timing.loadEventStart - performance.timing.fetchStart);}
  </script>
</body>
复制代码

大家可以调整资源摆放位置,观察浏览器的解析表现。

head 中资源的加载

  • head 中 js 资源加载都会停止后面 DOM 的构建,但是不影响后面资源的下载。
  • css资源不会阻碍后面 DOM 的构建,但是会阻碍页面的首次渲染。

body 中资源的加载

  • body 中 js 资源加载都会停止后面 DOM 的构建,但是不影响后面资源的下载。
  • css 资源不会阻碍后面 DOM 的构建,但是会阻碍页面的首次渲染。

DomContentLoaded 事件的触发

上面只是讲了 html 文档的加载与渲染,并没有讲 DOMContentLoaded 事件的触发时机。直截了当地结论是,DOMContentLoaded 事件在 html文档加载完毕,并且 html 所引用的内联 js、以及外链 js 的同步代码都执行完毕后触发

大家可以自己写一下测试代码,分别引用内联 js 和外链 js 进行测试。

load 事件的触发

当页面 DOM 结构中的 js、css、图片,以及 js 异步加载的 js、css 、图片都加载完成之后,才会触发 load 事件。

注意:

  • 页面中引用的js 代码如果有异步加载的 js、css、图片,是会影响 load 事件触发的。
  • video、audio、flash 不会影响 load 事件触发。

大家可以在 chrome 中试一下。

浏览器对同一域名下的资源并发下载线程数,chrome为6个。

  • 浏览器对同一域名下的下载并发不超过 6 个。超过 6 个的话,剩余的将会在队列中等待,这就是为什么我们要将资源收敛到不同的域名下,也是为了充分利用该机制,最大程度的并发下载所需资源,尽快的完成页面的渲染。

这里要注意关键词:同一域名。如果 n 个不同域名的话,在浏览器设置的最大并发上限以内(默认是10个),是可以达到 n * 6 个的最大并发的下载的。

posted @ 2021-11-05 23:06  浣熊sky  阅读(299)  评论(0编辑  收藏  举报