在 Chrome 浏览器的开发过程中,我们会看到 Network 面板中有这两个数值,分别对应网络请求上的标志线。这两个时间数值分别代表什么?
一、优化性能
我们一再强调将 CSS 放在头部,将 JS 文件放在尾部,这样有利于优化页面的性能。为什么这种方式能够优化性能?
二、jQuery 的 ready 方法原理
在用 jQuery 的时候,我们一般都会将函数调用写在 ready
方法内,这是什么原理?
DOMContentLoaded 的定义
顾名思义,DOMContentLoaded 就是 DOM 内容加载完毕。那么,什么是 DOM 内容加载完毕呢?
从打开一个网页说起。当输入一个 URL,页面的展示首先是空白的,然后过一会,页面会展示出内容,但是页面的有些资源比如说图片资源还无法看到。此时页面是可以正常交互的,过一段时间后,图片才完成显示在页面上。从页面空白到展示出页面内容,会触发 DOMContentLoaded 事件。而这段时间就是 HTML 文档被加载和解析完成。
HTML 文档加载和解析完成的定义
要解决这个问题,我们必须了解浏览器渲染原理。
- 当我们在浏览器地址栏输入 URL 时,浏览器会发送请求到服务器,服务器将请求的 HTML 文档发送回浏览器。
- 浏览器将文档下载下来后,从上到下解析,解析完成后会生成 DOM。
- 如果页面中有 CSS,会根据 CSS 的内容形成 CSSOM。
- DOM 和 CSSOM 会生成一个渲染树。
- 浏览器根据渲染树计算各节点的确切大小和位置,并将其绘制在浏览器上。
浏览器解析快照
在解析 HTML 的过程中,HTML 的解析会被中断,这是因为 JavaScript 会阻塞 DOM 的解析。
- 遇到
<script>
标签时,解析过程会停止,转而去处理脚本。 - 如果脚本是内联的,浏览器会先执行内联脚本;如果是外链的,则先加载脚本再执行。
- JavaScript 的执行会受到标签前面的样式文件影响。需要样式文件加载并解析完毕后才执行脚本。
为了减缓渲染被阻塞,现代浏览器使用猜测预加载。在解析被阻塞时,浏览器通过轻量级扫描器查找资源文件的 URL,并在渲染器使用前将其下载。
DOMContentLoaded 与 Load 的触发条件
- 当文档中没有脚本时,浏览器解析完文档便能触发 DOMContentLoaded 事件。
- 如果文档中包含脚本,则脚本会阻塞文档解析,且脚本需等待位于脚本前的 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 放在尾部?
面试中常提到将 JS 放在 <body>
标签底部,其原因如下:
浏览器生成 DOM 树时是一行一行读取 HTML 代码。将 JS 放在最后不会影响前面的页面渲染。
现代浏览器为了更好的用户体验,会尽快渲染部分内容以减少白屏时间。将 JS 放在后面能减少 First Paint 的时间,但不会影响 DOMContentLoaded 被触发的时间。
评论区