理解不一样的 HTML(1)| 青训营笔记

173 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的的第1天

✨ 前言

  • 2022-07-23AM 第一节课:HTML
  • 本文重点关注 vscode ! 自动补全 html 代码块的具体含义

✨ 时间线

了解 html 代码之前首先要讨论 时间线

何为时间线?

简单来说,浏览器开始加载页面的那一刻到页面加载完全结束的这个过程中,按照顺序发生的每一件事情

为什么了解时间线?

我们都知道,从输入 url 到浏览器呈现页面的过程,其中对于 html 如何解析每一行标签,影响着整个网页的加载速度

✨ script 标签

对于 <script> 标签想必大家都不陌生,但是关于 <script> 上面属性想必大家就了解甚少了,这里只提及两个属性,deferasync

  • 对于script 标签我们一般把他放在 <body> 内部,如果放在 <head> 内,则会阻塞代码执行,为什么会阻塞呢?
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.6/compiler-sfc.js">

因为对于外部引用的 <script>会同步下载 src 里面的脚本,并且会执行脚本里面的代码,因此阻塞浏览器阻塞的解析,怎么解决呢这个问题?

  • defer的意思:脚本会被延迟到整个页面都解析完毕后再运行,相当于告诉浏览器立即下载,但延迟执行(在浏览器解析到结束的</html> 标签后才会执行)

  • async:告诉浏览器立即开始下载,与 defer 不同的是,标记为 async 的脚本并不保证能按照它们出现的次序执行(告诉浏览器,不必等脚本下载和执行完后再加载页面,同样也不必等到该异步脚本下载和执行后再加载其他脚本),并且异步脚本不应该在加载期间修改 DOM。

图片1.png

  • 就像上面图片表示的意思,当遇到 script 标签 deferasync 都会开启异步下载,不会阻塞文档解析,但是脚本执行的时机各不相同

✨ 浏览器执行 html 代码顺序

先看一段代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.0-beta1/css/bootstrap-grid.css">
  <script type="text/javascript" href="https://cdn.bootcdn.net/ajax/libs/vue/2.7.6/compiler-sfc.js"></script>
</head>

<body>
  <img src="./1.jpg"/>
  <div></div>
</body>

</html>
  1. 浏览器在解析到这个文件的同时,会生成 document 对象,其实 js 文件开始起作用
  2. 读到第一行代码 <!DOCTYPE html>不是html标签)标志着浏览器解析文档的模式,如果不加这行代码,浏览器解析模式变为怪异模式 ,可以通过 document.compatMode 访问浏览器兼容模式(只读属性)
  3. 解析 html 标签,同时构建 dom 树,document.readyState = 'loading'
  4. 遇到 <link> 外部标签,开启新的线程异步加载 css 外部文件,生成 CSSOM(CSS 树)
  5. 遇到没有设置异步加载script 标签,阻塞文档解析,等待 js 脚本加载并且执行完成后,继续解析文档
  6. 异步加载<script>标签,异步加载 js 脚本并且执行,不阻塞文档解析,不能使用document.write
  7. 解析<body>里面的元素,解析文档遇到 img 标签,先解析这个节点,异步加载 src 里面的资源
  8. 文档解析,document.readyState = 'interactive'
  9. 带有 async 的脚本开始执行
  10. 文档解析完成后,触发 DOMContentLoaded 事件,同步的脚本文件执行阶段转向事件驱动阶段
  11. async script 加载并执行完成,img 等资源加载完毕,window 对象中的 onload 事件才触发,document.readyState = 'complete' 加载完成

✨ document.onreadystatechange() 事件

上述的浏览器执行过程提到了 onreadystatechange 事件,通过一段代码来验证上述内容

    console.log(document.readyState); // loading
    document.onreadystatechange = function () {
      console.log(document.readyState); // interactive complete
    }

    document.addEventListener('DOMContentLoaded', function () {
      console.log('DOMContentLoaded')
    }, false);

    window.onload = function () {
      console.log('onload');
      console.log(document.readyState); // complete
    }

输出顺序

image.png

注意点

  1. DOMContentLoaded 事件先与 onload 执行,大家有兴趣可以看下 jquery 中的入口函数源码,就是用了这个原理,减少白屏时间
  2. document.wirte()dom 树未构建完成前,向文档追加内容,而在 window.onload 中书写,清空所有内容,再追加