用户看到页面实际上可以分为两个阶段:页面内容加载完成和页面资源加载完成,分别对应于DOMContentLoaded和Load。
DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表,图片等
load事件触发时,页面上所有的DOM,样式表,脚本,图片都已加载完成
浏览器渲染的过程主要包括以下五步
1、浏览器将获取的HTML文档解析成DOM树。
2、处理CSS标记,构成层叠样式表模型CSSOM(CSS Object Model)。
3、将DOM和CSSOM合并为渲染树(rendering tree),代表一系列将被渲染的对象。
4、渲染树的每个元素包含的内容都是计算过的,它被称之为布局layout。浏览器使用一种流式处理的方法,只需要一次绘制操作就可以布局所有的元素。
5、将渲染树的各个节点绘制到屏幕上,这一步被称为绘制painting。
注意:以上五个步骤并不一定一次性顺序完成,比如DOM或CSSOM被修改时,亦或是哪个过程会重复执行,这样才能计算出哪些像素需要在屏幕上进行重新渲染。
而在实际情况中,JavaScript和CSS的某些操作往往会多次修改DOM或者CSSOM
重绘(repaint):屏幕的一部分要重绘。渲染树节点发生改变,但不影响该节点在页面当中的空间位置及大小。
譬如某个div标签节点的背景颜色、字体颜色等等发生改变,但是该div标签节点的宽、高、内外边距并不发生变化,此时触发浏览器重绘(repaint)。
重排(reflow)【回流又称为重排】:当渲染树节点发生改变,影响了节点的几何属性(如宽、高、内边距、外边距、或是float、position、display:none;等等),导致节点位置发生变化,此时触发浏览器重排(reflow),需要重新生成渲染树。
譬如JS为某个p标签节点添加新的样式:"display:none;"。导致该p标签被隐藏起来,该p标签之后的所有节点位置都会发生改变。此时浏览器需要重新生成渲染树,重新布局,即重排(reflow)。
重排和重绘的必然关系
注意:重排必将引起重绘,而重绘不一定会引起重排。
什么情况下会引起重排
当页面布局和几何属性改变时就需要重排;如下
1、添加或者删除可见的DOM元素;
2、元素位置改变——display、float、position、overflow等等;
3、元素尺寸改变——边距、填充、边框、宽度和高度
4、内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;
5、页面渲染初始化;
6、浏览器窗口尺寸改变——resize事件发生时;
如何减少和避免重排
Reflow 的成本比 Repaint 的成本高得多的多。一个节点的 Reflow 很有可能导致子节点,甚至父节点以及兄弟节点的 Reflow 。
在一些高性能的电脑上也许还没什么,但是如果 Reflow 发生在手机上,那么这个过程是延慢加载和耗电的。
1、直接改变className,如果动态改变样式,则使用cssText(考虑没有优化的浏览器);
2、让要操作的元素进行”离线处理”,处理完后一起更新;
a) 使用DocumentFragment进行缓存操作,引发一次回流和重绘;
b) 使用display:none技术,只引发两次回流和重绘;
c) 使用cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;
3、不要经常访问会引起浏览器flush队列的属性,如果你确实要访问,利用缓存;
4、让元素脱离动画流,减少回流的Render Tree的规模;
浏览器工作流程:构建DOM -> 构建CSSOM -> 构建渲染树 -> 布局 -> 绘制
渲染页面时常见的不良现象
由于浏览器的渲染机制不同,在渲染页面时会出现两种常见的不良现象—-白屏问题和FOUS(无样式内容闪烁)
FOUC:由于浏览器渲染机制(比如firefox),再CSS加载之前,先呈现了HTML,就会导致展示出无样式内容,然后样式突然呈现的现象;
白屏:有些浏览器渲染机制(比如chrome)要先构建DOM树和CSSOM树,构建完成后再进行渲染,如果CSS部分放在HTML尾部,由于CSS未加载完成,浏览器迟迟未渲染,从而导致白屏;也可能是把js文件放在头部,脚本会阻塞后面内容的呈现,脚本会阻塞其后组件的下载,出现白屏问题。
如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件,这也是都建议将 script 标签放在 body 标签底部的原因;
解释:
JavaScript的加载、解析与执行会阻塞DOM的构建,也就是说,在构建DOM时,HTML解析器若遇到了JavaScript,那么它会暂停构建DOM,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建;
并不是说 script 标签必须放在底部,因为还可以给 script 标签添加 defer 或者 async 属性
JS文件不只是阻塞DOM的构建,它会导致CSSOM也阻塞DOM的构建;
在没有defer或者async的情况下,会立即执行脚本,所以通常建议把script放在body最后
<script src="script.js"></script>
有async的话,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。
但是多个js文件的加载顺序不会按照书写顺序进行
<script async src="script.js"></script>
有derer【延迟加载】的话,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成,并且多个defer会按照顺序进行加载
<script defer src="script.js"></script>
区别主要在于一个执行时间,defer会在文档解析完之后执行,并且多个defer会按照顺序执行,而async则是在js加载好之后就会执行,并且多个async,哪个加载好就执行哪个
蓝色线代表网络读取,
红色线代表执行时间,这俩都是针对脚本的
绿色线代表 HTML 解析
常见的http状态码相关:
200 表示成功
301 302 重定向
304 从浏览器缓存加载
401 用户没有访问权限
403 权限不够,拒绝访问
404 资源未找到
500 服务器内部错误
常见的 Content-Type 类型
针对axios讲
1、application/json是Axios默认的Content-Type --->Request Payload
2、Content-Type: application/x-www-form-urlencoded --->Form Data 原始表单
入参处理 data: qs.stringify(data) 一旦使用qs库的方法,就应该注意不能对请求体中的数据使用扩展运算符(...)
另外一种处理方法
let data = new URLSearchParams();
data.append('key1', 'value1');
data.append('key2', 'value2');
3、Content-Type: multipart/form-data --->Form Data
一般用来上传文件,指定传输数据为二进制数据,例如图片、mp3、文件等
let data = new FormData();
data.append('fileName', document.querySelector('input[type=file]').files[0]);
data.append('key1', 'value1');
data.append('key2', 'value2');
通常的
最常见的 POST 提交数据的方式,原生Form表单key1=val1&key2=val2 的方式进行编码 比如axios的 Qs.stringify(data)
1、application/x-www-form-urlencoded (如?type=aa&bb)
主体是序列化后的 JSON 字符串
2、application/json (如:{age:20,sex:'男'})
当上传的字段是文件时,会有Content-Type来说明文件类型;Content-disposition
3、multipart/form-data (如:文件提交)
既可以上传键值对,也可以上传文件,甚至多个文件,传输和存储数据,它非常适合万维网传输
4、text/xml
二进制文件类型。如application/pdf application/octet-stream
5、binary (application/octet-stream)
关于URL的几个重要概念
一个完整的URL包括协议【http/https】、服务器地址(主机)【www.xxx.com/cn】、端口【8080】、路径【/xx】;
例子:http://www.baidu.com:8080/user/search.html?a=1&b=2#results
hash:URL的锚部分,包括开头的哈希(#)号,例如:"#results"。
host:URL的主机端口部分,例如:"http://www.baidu.com:8080";
hostname:URL的主机名部分,例如:"http://www.baidu.com";
href:文档的URL的完整文本,不同于其他的指定URL的一部分Location属性。将这个属性设置为一个新的URL将导致浏览器读取并显示心得URL内容。把这个值直接赋值给Location对象将设置这个属性,把一个Location对象用作一个字符串将使用这个属性的值。
pathname:URL的路径名部分,例如"/user/search.html";
port:URL的端口部分,例如"8080";
protocol:URL协议部分,包括尾部的冒号,例如"http:";
search:URL的查询部分,包括开头的问号,例如"?a=1&b=2"。
输入url到页面完成发生了什么
(1)DNS解析:将域名解析为ip地址
(2)建立TCP连接: 客户端浏览器与WEB服务器建立TCP(传输控制协议)连接,三次握手【浏览器-->服务器,服务器-->浏览器,浏览器-->服务器】
(3)发送请求:请求报文 http协议的通信内容
(4)响应请求:响应报文
(5)渲染页面:dom树、css树、合并渲染树计算布局 绘制;
(6)断开连接【非持久性】: TCP四次挥手。【浏览器-->服务器,服务器-->浏览器,服务器-->浏览器,浏览器-->服务器】
http对应于应用层,Tcp协议对应于传输层,http协议是在Tcp协议之上建立的;
浏览器内核
1、webkit(v8引擎):chrome opera safari 国产浏览器和手机端
2、gecko: firefox(火狐浏览器)
3、trident: IE浏览器(IE的最新版本是edge)
页面的渲染过程
第一步:在CPU开辟一块栈内存,并分配一个主线程,基于进栈出栈的方式自上而下的解析代码
第二步:第一次加载页面时,代码首先渲染出所有的DOM结构,当CSS资源请求回来后生成样式树,最后把DOM树和样式树混合在一起生成渲染树
第三步:通知GPU(显卡)绘制出来即可
为啥会出现浏览器兼容
(1)部分浏览器会提前开发一些更好的功能,后期这些功能会被收录到W3C规范中,但在收录之前会存在一定的兼容性
(2)各个浏览器厂商为了突出自己的独特性,用其他方法实现了W3C规范中的功能
内容有点多!耐心看完希望会有收获~自己总结常用知识点储备~如有不对请指明;转载注明出处~