侧边栏壁纸
  • 累计撰写 225 篇文章
  • 累计创建 275 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

聊聊DOMContentLoaded与load的区别

DGF
DGF
2020-03-05 / 0 评论 / 0 点赞 / 25 阅读 / 0 字

post151-1.png
在 Chrome 浏览器的开发过程中,我们会看到 Network 面板中有这两个数值,分别对应网络请求上的标志线。这两个时间数值分别代表什么?

一、优化性能

我们一再强调将 CSS 放在头部,将 JS 文件放在尾部,这样有利于优化页面的性能。为什么这种方式能够优化性能?

二、jQuery 的 ready 方法原理

在用 jQuery 的时候,我们一般都会将函数调用写在 ready 方法内,这是什么原理?

DOMContentLoaded 的定义

顾名思义,DOMContentLoaded 就是 DOM 内容加载完毕。那么,什么是 DOM 内容加载完毕呢?
从打开一个网页说起。当输入一个 URL,页面的展示首先是空白的,然后过一会,页面会展示出内容,但是页面的有些资源比如说图片资源还无法看到。此时页面是可以正常交互的,过一段时间后,图片才完成显示在页面上。从页面空白到展示出页面内容,会触发 DOMContentLoaded 事件。而这段时间就是 HTML 文档被加载和解析完成。

HTML 文档加载和解析完成的定义

要解决这个问题,我们必须了解浏览器渲染原理。

  1. 当我们在浏览器地址栏输入 URL 时,浏览器会发送请求到服务器,服务器将请求的 HTML 文档发送回浏览器。
  2. 浏览器将文档下载下来后,从上到下解析,解析完成后会生成 DOM。
  3. 如果页面中有 CSS,会根据 CSS 的内容形成 CSSOM。
  4. DOM 和 CSSOM 会生成一个渲染树。
  5. 浏览器根据渲染树计算各节点的确切大小和位置,并将其绘制在浏览器上。

post151-2.png

浏览器解析快照

post151-3.png
在解析 HTML 的过程中,HTML 的解析会被中断,这是因为 JavaScript 会阻塞 DOM 的解析。

  • 遇到 <script> 标签时,解析过程会停止,转而去处理脚本。
  • 如果脚本是内联的,浏览器会先执行内联脚本;如果是外链的,则先加载脚本再执行。
  • JavaScript 的执行会受到标签前面的样式文件影响。需要样式文件加载并解析完毕后才执行脚本。

为了减缓渲染被阻塞,现代浏览器使用猜测预加载。在解析被阻塞时,浏览器通过轻量级扫描器查找资源文件的 URL,并在渲染器使用前将其下载。

DOMContentLoaded 与 Load 的触发条件

  1. 当文档中没有脚本时,浏览器解析完文档便能触发 DOMContentLoaded 事件。
  2. 如果文档中包含脚本,则脚本会阻塞文档解析,且脚本需等待位于脚本前的 CSS 加载完才能执行。

注意:DOMContentLoaded 的触发不需要等待图片等其他资源加载完成。

页面上所有资源(图片、音频、视频等)被加载以后才会触发 load 事件,因此 load 事件会在 DOMContentLoaded 被触发后才触发。


jQuery 的 DOMContentLoaded 与 Load

  • $(document).ready(function() { // ...代码... }); 监听的是 DOMContentLoaded 事件。
  • $(document).load(function() { // ...代码... }); 监听的是 load 事件。

实现 DOMContentLoaded 和 Load

1. onload 事件

onload 事件所有浏览器都支持,通过调用如下实现:

window.onload = function() {
   // 代码
};

2. DOMContentLoaded 事件

由于不同浏览器对 DOMContentLoaded 支持不同,需要兼容性处理:

function ready(fn) {
   if (document.addEventListener) {
       document.addEventListener('DOMContentLoaded', function() {
           document.removeEventListener('DOMContentLoaded', arguments.callee, false);
           fn();
       }, false);
   } else if (document.attachEvent) {
       document.attachEvent('onreadystatechange', function() {
           if (document.readyState === 'complete') {
               document.detachEvent('onreadystatechange', arguments.callee);
               fn();
           }
       });
       if (document.documentElement.doScroll && typeof window.frameElement === "undefined") {
           try {
               document.documentElement.doScroll('left');
           } catch (error) {
               return setTimeout(arguments.callee, 20);
           }
           fn();
       }
   }
};

为什么将 CSS 放在头部,将 JS 放在尾部?

post151-4.png
面试中常提到将 JS 放在 <body> 标签底部,其原因如下:
浏览器生成 DOM 树时是一行一行读取 HTML 代码。将 JS 放在最后不会影响前面的页面渲染。

现代浏览器为了更好的用户体验,会尽快渲染部分内容以减少白屏时间。将 JS 放在后面能减少 First Paint 的时间,但不会影响 DOMContentLoaded 被触发的时间。

0

评论区