页面渲染层面
渲染时机相关
懒加载
懒执行
渐进式渲染
html dom 树,css cssom 树 defer async 等等 遇到 js,preload 以及 prefetch 并发加载 重绘和回流 浏览器缓存
页面渲染阶段
- css 在上、js 在下
- 加载 css 推荐用 link 少用 @import
- link 属于 html,@import 属于 css,需写在样式表开头
- @import 是 css2.1 才出现的概念
- 当 html 文件被加载时,link 引用的文件会同时被加载,而@import 引用的文件则会等页面全部下载完毕再被加载
- 不重要的外置引入的 js 使用 defer 或者 async 属性异步加载
script
特性(attribute)可以为我们解决延迟问题:defer
和 async
defer
defer
特性告诉浏览器不要等待脚本。相反,浏览器将继续处理 HTML,构建 DOM。脚本会“在后台”下载,然后等 DOM 构建完成后,脚本才会执行
换句话说:
- 具有
defer
特性的脚本不会阻塞页面 - 具有
defer
特性的脚本总是要等到 DOM 解析完毕,但在DOMContentLoaded
事件之前执行
下面这个示例演示了上面所说的第二句话:
<p>...content before scripts...</p>
<script>
document.addEventListener('DOMContentLoaded', () =>
alert('DOM ready after defer!'),
);
</script>
<script
defer
src="https://javascript.info/article/script-async-defer/long.js?speed=1"
></script>
<p>...content after scripts...</p>
- 页面内容立即现实
DOMContentLoaded
事件处理程序等待具有defer
特性的脚本执行完成。它仅在脚本下载且执行结束后才会被触发
具有 defer
特性的脚本保持其相对顺序,就像常规脚本一样。
defer
特性仅适用于外部脚本
如果 <script>
脚本没有 src
,则会忽略 defer
特性。
async
async
特性与 defer
有些类似。它也能够让脚本不阻塞页面,但是,在行为上二者有着重要的区别
async
特性意味着脚本是完成独立的
- 浏览器不会因
async
脚本而阻塞(与defer
类似) - 其他脚本不会等待
async
脚本加载完成,同样,async
脚本也不会等待其他脚本 DOMContentLoaded
可能会发生在异步脚本之前(如果异步脚本在页面完成后才加载完成)DOMContentLoaded
也可能发生在异步脚本之后(如果异步脚本很短,或者是从 HTTP 缓存中加载的)
换句话说,async
脚本会在后台加载,并在加载就绪时运行。DOM 和其他脚本不会等待它们,它们也不会等待其他的东西。async
脚本就是一个会在加载完成时执行的完全独立的脚本
动态脚本
我们可以使用 JavaScript 动态地创建一个脚本,并将其插入(append)到文档(document)中:
let script = document.createElement('script');
script.src = '/article/script-async-defer/long.js';
document.body.append(script); // (*)
默认情况下,动态脚本的行为是“异步”的。
也就是说:
- 它们不会等待任何东西,也没有上面东西会等它们
- 先加载完成的脚本先执行(“加载优先”顺序)
总结
async
和 defer
有一个共同点:加载这样的脚本都不会阻塞页面的渲染。因此,用户可以立即圆度并了解页面内容。但是,它们之前也存在一些本质的区别:
顺序 | DOMContnetLoaded | |
---|---|---|
async | 加载优先顺序。脚本在文档中的顺序不重要——先加载完成的先执行 | 不相关。可能在文档加载完成前加载并执行完毕。如果脚本很小或者来自缓存,同时文档足够长,就会发生这种情况 |
defer | 文档顺序(它们在文档中的顺序) | 在文档加载和解析完成之后(如果需要,则会等待),即在DOMContentLoaded 之前执行 |
在实际开发中,defer
用于需要整个 DOM 的脚本,脚本的相对执行顺序很重要的时候使用
async
用于独立脚本,例如计数器或广告,这些脚本的相对执行顺序无关紧要