性能优化之html、css、js三者的加载顺序
前言
我们知道一个页面通常由,html,css,js三部分组成,一般我们会把css文件放在head头部加载,而js文件则放在页面的最底部加载,想要知道为什么大家都会不约而同的按照这个标准进行构建页面,必须先得了解页面的加载过程。(当然以现在的技术你也可以不按这个标准,下面会有讲到js的异步加载问题)
之前写过一篇超详细讲解页面加载过程,这里会比较详细的介绍从输入URL到展现一个页面的详细过程,今天我们主要来看一下页面的构建过程,以及html,css,js三者之间的关系。
如果这篇文章有帮助到你,️关注+点赞️鼓励一下作者,文章公众号首发,关注 前端南玖
第一时间获取最新文章~
页面构建过程
这里我们主要考虑三种情况下的构建过程
页面中只含有外部CSS文件
从图中我们可以看到,在构建布局树之前需要先获取到DOM树与CSSOM树,在请求回HTML文件时,HTML解析器响应HTML数据开始构建DOM,但是由于此时页面中包含的是外部CSS文件,所以他需要先去请求CSS会见,再获取到CSS数据后CSS解析器才能开始构建CSSOM。所以这种情况下CSS没有阻塞DOM的构建,但它阻塞了页面的渲染
页面中包含内联JS和外部CSS
从这张图中我们可以看到,HTML解析器在构建DOM过程中如果遇到了JS就会停止构建DOM,先去解析执行JS(因为JS可能会修改DOM)。但是在执行JS脚本之前,如果页面中包含外部CSS或内联CSS,会先将CSS构建成CSSOM,再去执行JS。这也就是上面说到的为什么一般将JS文件放在页面的最底部的原因。
所以从这种情况来看,CSS、JS会阻塞DOM的构建,CSS会阻塞JS的执行,但它们不会阻塞HTML的解析
页面中包含外部JS与外部CSS
从这张图我们可以看到,HTML解析器在解析过程中如果遇到外部CSS与外部JS文件,就会同时发起请求对文件进行下载,这个过程DOM构建的过程会停止,需要等CSS文件下载完成并构建完CSSOM,JS文件下载完成并执行结束,才会开始构建DOM。我们知道CSS会阻塞JS的执行,所以JS必须要等到CSSOM构建完成之后再执行
所以上面我们说的CSS放在头部进行加载,而JS文件放在页面的底部进行加载也就能够解释的通了。
CSS与DOM的关系
CSS
不会阻塞DOM
的解析,但会阻塞DOM
的渲染
CSSOM的作用
- 第一个是提供给JavaScript操作样式表的能力
- 第二个是为布局树的合成提供基础的样式信息
- 这个CSSOM体现在DOM中就是
document.styleSheets
由之前讲到的浏览器渲染流程我们可以看出:
- DOM和CSSOM通常是并行构建的,所以CSS加载不会阻塞DOM的解析
- render树是依赖DOM树和CSSOM树的,所以它必须等到两者都加载完毕才能开始构建渲染,所以CSS加载会阻塞DOM的渲染
CSS与JS的关系
CSS
会阻塞JS
执行,但不会阻塞JS
文件的下载
由于JavaScript是可以操作DOM与CSS的,如果在修改这些元素属性同时渲染界面(即JavaScript线程与UI线程同时进行),那么渲染线程前后获得的元素可能就不一致了。所以为了防止渲染出现不可预期的结果,浏览器设置GUI渲染线程与JavaScript线程为互斥的关系
如果JS
脚本的内容是获取元素的样式,那它就必然依赖CSS
。因为浏览器无法感知JS
内部到底想干什么,为避免样式获取,就只好等前面所有的样式下载完毕再执行JS
。但JS文件与CSS文件下载是并行的,CSS文件会在后面的JS文件执行前先加载执行完毕,所以CSS会阻塞后面JS的执行。
JS与DOM的关系
JS会阻塞DOM的解析,因此也就会阻塞页面的加载
这也是为什么我们常说要把JS文件放在最下面的原因
由于 JavaScript 是可操纵 DOM 的,如果在修改这些元素属性同时渲染界面(即 JavaScript 线程和 UI 线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。
因此为了防止渲染出现不可预期的结果,浏览器设置 GUI 渲染线程与 JavaScript 引擎为互斥的关系。
当 JavaScript 引擎执行时 GUI 线程会被挂起,GUI 更新会被保存在一个队列中等到引擎线程空闲时立即被执行。
当浏览器在执行 JavaScript 程序的时候,GUI 渲染线程会被保存在一个队列中,直到 JS 程序执行完成,才会接着执行。
因此如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
结论
- CSS不会阻塞DOM的解析,但会阻塞DOM的渲染
- CSS会阻塞JS的执行,但不会阻塞JS的下载
- JS会阻塞DOM的解析,也就会阻塞DOM的渲染
由于CSS与JS都会阻塞DOM的渲染,我们应该尽可能的提高CSS的加载速度,将JS延迟加载。
优化CSS加载
使用CDN(CDN会根据用户网络状况挑选最近的一个具有缓存内容的节点,可以减少加载时间)
压缩CSS文件(可以用很多打包工具,比如webpack,gulp等,也可以通过开启gzip压缩)
合理使用缓存(设置cache-control,expires,以及E-tag都是不错的,不过要注意一个问题,就是文件更新后,你要避免缓存而带来的影响。其中一个解决防范是在文件名字后面加一个版本号)
减少http请求数,将多个css文件合并,或者是干脆直接写成内联样式(内联样式的一个缺点就是不能缓存)
CSS优化部分推荐阅读CSS性能优化的几个技巧
JS延迟加载
在HTML中加载外部JS文件的方式一般有三种:
<script src="..."></script>
<script src="..." async></script>
<script src="..." defer></script>
<script>
(默认脚本)
从上图可知,HTML解析器在解析过程中如果遇到script
标签️,就会暂停解析,先去请求下载script
脚本,下载完接着执行该脚本代码,执行完之后再继续解析HTML。
所以script 阻塞了浏览器对 HTML 的解析,如果获取 JS 脚本的网络请求迟迟得不到响应,或者 JS 脚本执行时间过长,都会导致白屏,用户看不到页面内容。
<script async>
(异步脚本)
从上图可知,HTML解析器在解析过程如果遇到script async
标签,该脚本的请求下载是异步的,不会阻塞HTML的解析,但是如果脚本下载回来时,HTML还没有解析完成,这时候会暂停HTML的解析,先去执行脚本内容,执行完成后,再继续解析HTML。
当然它还有一种情况就是当异步脚本下载回来时,HTML解析已经完成了,那该脚本就对HTML没啥影响,下载完直接执行就好了。
所以该方法的执行是不可控的,因为无法确定脚本的下载速度与脚本内容的执行速度,如果存在多个script async
时,他们之间的执行的顺序也是不可控的,完全取决于各自的下载速度,谁先下载完成就先执行谁。
<script defer>
(异步延迟脚本)
从上图可知,HTML解析器在解析过程如果遇到script defer
标签,该脚本的请求下载也是异步的,不会阻塞HTML的解析,并且在脚本下载完之后如果HTML还没解析完成,该脚本也不会阻塞HTML解析,而是会等HTML解析完成之后再执行。
如果存在多个script defer
标签时,他们之间的执行顺序会按他们在HTML文档中的顺序来进行,这样能够保证JS脚本之间的依赖关系。
总结
- 如果脚本是模块化的,并且脚本之间没有依赖关系,使用
async
- 如果脚本之间有依赖关系,使用
defer
- 如果脚本内容比较小,并且被一个异步脚本依赖,使用
默认脚本
(不放任何属性)
脚本类型 | 是否阻塞HTML的解析 | 脚本的执行顺序 |
---|---|---|
<script>
|
是 | 与在HTML文档中的顺序一致 |
<script async>
|
可能阻塞也可能不阻塞 | 与网络请求回脚本文件的顺序一致 |
<script defer>
|
否 | 与在HTML文档中的顺序一致 |
推荐阅读
- HTTP发展史,HTTP1.1与HTTP2.0的区别
- 超全面总结Vue面试知识点,助力金三银四
- 【面试必备】前端常见的排序算法
- CSS性能优化的几个技巧
- 前端常见的安全问题及防范措施
- 为什么大厂前端监控都在用GIF做埋点?
- 前端人员不要只知道KFC,你应该了解 BFC、IFC、GFC 和 FFC
我是南玖,我们下期见!!!
性能优化之html、css、js三者的加载顺序的更多相关文章
- 关于html,css,js三者的加载顺序问题
<head lang="en"> <meta charset="utf-8"> <title></title> ...
- 前端性能优化成神之路--图片懒加载(lazyload image)
图片懒加载(当然不仅限于图片,还可以有视频,flash)也是一种优化前端性能的方式.使用懒加载可以想要看图片时才加载图片,而不是一次性加载所有的图片,从而在一定程度从减少服务端的请求 什么是懒加载 懒 ...
- 对于HTML页面中CSS, JS, HTML的加载与执行过程的简单分析
来自 https://blog.csdn.net/u011088260/article/details/79563315 最近在研究HTML页面中JavaScript的执行顺序问题.在Java ...
- web性能优化之---JavaScript中的无阻塞加载性能优化方案
一.js阻塞特性 JS 有个很无语的阻塞特性,就是当浏览器在执行JS 代码时,不能同时做其他任何事情,无论其代码是内嵌的还是外部的. 即<script>每次出现都会让页面等待脚本的解析和执 ...
- 用 Flask 来写个轻博客 (28) — 使用 Flask-Assets 压缩 CSS/JS 提升网页加载速度
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 Flask-Assets 将 Flask-Assets 应用 ...
- nuxt 优化项:禁用js的预加载
这里有个nuxt和vue不同的地方,这个地方很有意思,官方的中文文档说得蜜汁自信 ------------------------------- In production, nuxt.js uses ...
- JS 和 CSS 的位置对其他资源加载顺序的影响
JS 和 CSS 在页面中的位置,会影响其他资源(指 img 等非 js 和 css 资源)的加载顺序,究其原因,有三个值得注意的点: JS 有可能会修改 DOM. 典型的,可能会有 document ...
- js 外部文件加载处理
概述 前端在日常工作中很大一部分时间是在思考页面的优化方案,让页面载入得更快.鉴于javascript是单线程的事件驱动语言,优化工作之一就是:控制图片.swf.iframe等大流量文件以及js和cs ...
- 网页加载速度优化2--先加载css,然后再加载js文件。
网页加载时,是按从上到下,从左到右的顺序加载的.所以一定要先加载css文件(不要让用户看到一个杂乱无章的页面),最后再加载js文件,js一般都是处理功能的,所以不需要提前加载.先给用户观感,再给用户上 ...
随机推荐
- 将su模型导入arcgis,并获取高度信息,多面体转shp文件(ArcMap)
问题:将Sketchup中导出的su模型,导入arcgis并得到面shp文件,进而获取各建筑的高度.面积等信息. 思路: (1)导入arcgis得到多面体 (2)转为面shp文件 (3)计算高度/面积 ...
- 空间插值生物X适宜性分析
1 前言 这期博主将根据示例大概讲一下插值分析. 2 问题阐述 根据要求,完成以下操作: (1)请就以上条件确定此地区适合X的生活范围,并制作专题图.专题图内容要求以地形和水系作为背景,且给出适宜区域 ...
- 与Flash 中国特供版斗智斗勇
我的Windows 有OEM和学校KMS 的正版,Office 365 年年续费,QQ音乐腾讯视频哔哩哔哩月月开会员,软件游戏都从Play 商店和Steam 上购买.但是Adobe 这个垃圾合作,终于 ...
- MySQL CREATE TABLE 简单设计模板交流
推荐用 MySQL 8.0 (2018/4/19 发布, 开发者说同比 5.7 快 2 倍) 或同类型以上版本. CREATE TABLE TEMPLATE CREATE TABLE [table ...
- MySQL存储引擎,索引及基本优化策略
存储引擎 与Oracle, SQL Server这些数据库不同,MySQL提供了多种存储引擎.什么是存储引擎?存储引擎其实就是一套对于数据如何存储,查询,更新,建立索引等接口的实现.不同存储引擎特性有 ...
- Docker重要容器命令
镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 容器重要命令 启动守护式容器 docker run -d 镜像 docker run -d image [command][arg...] 使用c ...
- Pulsar 也会重复消费?
背景 许久没有分享 Java 相关的问题排查了,最近帮同事一起排查了一个问题: 在使用 Pulsar 消费时,发生了同一条消息反复消费的情况. 排查 当他告诉我这个现象的时候我就持怀疑态度,根据之前使 ...
- DLink 815路由器栈溢出漏洞分析与复现
DLink 815路由器栈溢出漏洞分析与复现 qemu模拟环境搭建 固件下载地址 File DIR-815_FIRMWARE_1.01.ZIP - Firmware for D-link DIR-81 ...
- jQuery--筛选【查找函数】
查找函数介绍 <A> <B> <C></C> <D></D> <E></E> <F>< ...
- 学习zabbix(二)
超大规模门户网站集群架构: 运维30%的时间都在监控,监控要多维度: 监控(单机监控(系统监控).网络监控.应用监控.分布式监控): 业务监控(业务指标-->流量分析-->舆论监控): 流 ...