原稿:语雀 · 页面生命周期 · 原目录:JavaScript › 页面生命周期

脚本加载

参考链接:MDN:<script>

解析 html 时,文档中的 js 资源会阻塞当前解析直到脚本下载执行完毕,通过 defer 和 async 可以进行优化:

共同点:这两类脚本都能够在后台加载,不会阻塞页面的渲染。因此,用户可以立即阅读并了解页面内容。

defer

  1. 脚本会被延迟到整个页面都解析完毕后再运行,即先下载,但只能在 DOM 解析完毕后再执行
  2. defer脚本总是要等到 DOM 解析完毕,但在 DOMContentLoaded 事件之前执行
  3. 多个defer脚本会保持其相对顺序,就像常规脚本一样

async

  1. async 脚本都是独立的,脚本在后台加载,并在加载就绪时运行
  2. DOMContentLoaded 和异步脚本不会彼此等待:
  • 可能会发生在异步脚本之前(如果异步脚本在页面完成后才加载完成)
  • 也可能发生在异步脚本之后(如果异步脚本很短,或者是从 HTTP 缓存中加载的)
  1. 多个 async 脚本独立,谁先加载完毕就会执行
页面生命周期 配图

页面生命周期事件

HTML 页面的生命周期包含三个重要事件:

(1)DOMContentLoaded —— 浏览器已完全加载 HTML,并构建了 DOM 树,但像 <img> 和样式表之类的外部资源可能尚未加载完成
(2)load —— 浏览器不仅加载完成了 HTML,还加载完成了所有外部资源:图片,样式,js等
(3)beforeunload/unload —— 当用户正在离开页面时

每个事件的含义的:

  • DOMContentLoaded :DOM 已经就绪,因此处理程序可以查找 DOM 节点,并初始化接口。
  • load : 外部资源已加载完成,样式已被应用,图片大小也已知了。
  • beforeunload :用户正在离开:我们可以检查用户是否保存了更改,并询问他是否真的要离开。
  • unload :用户几乎已经离开了,但是我们仍然可以启动一些操作,例如发送统计数据。

DOMContentLoaded

DOMContentLoaded:只要页面中的 DOM 结构加载完成后就可以触发

document.addEventListener('DOMContentLoaded', function () {
  console.log('DOM结构加载完成了')
});

但是 html 的解析本身会被脚本加载所阻塞,因此文档中遇到 <script> 标签时,DOMContentLoaded 必须等待脚本加载执行结束,但是对有 <async> 特性的脚本,DOMContentLoaded 不会被阻塞。

window.onload

onload()是页面整个页面(包括图片、CSS)加载完毕后触发

window.onload = function () {
  console.log('加载完成了')
};

小结

  • 页面生命周期事件中 DOMContentLoaded 会在 DOM 结构生成后就触发,而 load 会在加载完成了所有外部资源(图片、样式、js)后触发
  • <script defer> 和 <script async> 都能开启对文档中脚本资源的异步并行下载,区别是:async 属性的脚本会在下载完毕后尽快执行,多个脚本之间的顺序不能保证;defer 属性的脚本一定会在完成页面 DOM 结构加载后,触发 DOMContentLoaded 前执行