个人笔记,不断学习总结各种大前端优化方案,有兴趣的可以了解学习,没兴趣的出门右拐,当然,各位大佬有心探讨交流,留言分享好的文章,感激不尽。
1.cookie
1.1 为啥会产生cookie?
由于HTTP1.X是一个无状态协议,也就是客户端同一个请求发送多次,服务端并不能识别是不是同一个客户端发送,为了解决无状态情况,出现了cookie
1.2 cookie设置流程
客户端请求服务端 -> 服务端回应头部set-cookie -> 客户端收到并保存到本地 -> 客户端请求携带头部字段cookie
1.3 cookie属性
属性 | 解释 |
---|---|
expires | 有效期,以客户端为准 |
max-Age | 正数s,负数s立刻删除,0为会话cookie即关闭浏览器就是消失 |
Domin | cookie送达的主机名 |
Path | 携带cookie的资源路径 |
Secure | 标记为Secure只会https发送 |
HttpOnly | 标记为HttpOnly前端无法通过document.cookie获取,避免xss攻击 |
SameSite | Chrome80新加入的属性 |
1.4 cookie作用
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
1.5 SameSite
比如当前网页www.renrendai.com为一方请求,请求后端必然根据设置的domin和path会携带对应的cookie,但是比如通过www.baidu.com等三方网站点击跳转到www.renrendai.com的请求会根据SameSite的设定一方请求是否携带cookie;
所谓同站(一方)就是顶级域名和二级域名相同 eg: a.taobao.com 和 b.taobao.com 顶级域名为.com, 二级域名为taobao, 也就是前面截去.后面截去顶级域名,中间部分为二级域名 a.a.xx.cn二级域名为a.xx
- 异步请求(不会改变当前页面,也不会打开新页面),比如通过
<script>、<link>、<img>、<iframe>
等标签发起的请求,还有通过各种发送 HTTP 请求的 DOM API(XHR,fetch,sendBeacon)发起的请求。 - 同步请求(可能改变当前页面,也可能打开新页面),比如通过对
<a>
的点击,对<form>
的提交,还有改变 location.href,调用 window.open() 等方式产生的请求。
SameSite三个值
- strict所有三方的链接都不会携带cookie,比如你当前淘宝处于登录态,但是从百度跳转到淘宝的页面却没有登录态,因而无法发起csrf攻击
- lax只有同步且是get请求才可携带cookie
- none所有三方的请求都会携带cookie
2. script标签的defer和async区别
<script>
标签打开defer或async属性,脚本就会异步加载。渲染引擎遇到这一行命令,就会开始下载外部脚本,但不会等它下载和执行,而是直接执行后面的命令
2.1 defer与async的区别是:
defer要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行;async一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的
script的type='module'等同于defer,并且能够加载es6模块
3.EventLoop
3.1 执行步骤
- 初始的时候整个宏任务队列只有一个script任务
- 宏任务执行过程中遇到微任务直接加入微任务队列
- 一个宏任务执行完,查看微任务队列有任务,把所有微任务清理掉
- GUI(图形用户界面)渲染
- 继续执行宏任务队列第二个任务,依次循环
- 宏任务:setTimeout,setInterval,I/O,UI交互事件,postMessage,MessageChannel,setImmediate
- 微任务:Promise.then,MutationObserver,process.nextTick
- window.requestAnimationFrame()要求浏览器在下次重绘之前调用指定的回调函数更新动画
4.require与import区别
- CommonJS 模块是运行时加载,会缓存,可动态加载,ES6 模块是编译时输出接口
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用
- 关于commonjs和es6的模块循环引用
5. 浏览器渲染
5.1 浏览器渲染过程
- 解析HTML,生成DOM树,解析CSS,生成CSSOM树
- 将DOM树和CSSOM树结合,生成渲染树(Render Tree)
- Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
- Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
- Display:将像素发送给GPU,展示在页面上。
回流: 计算dom节点在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流。 重绘: 计算它们在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流。
5.2 什么情况下发送回流重绘
- 添加和删除可见的dom元素
- 元素的位置发生变化
- 元素的尺寸发生变化(宽,高,内外边距,边框大小)
- 内容发生变化(文本或者图片)
- 页面一开始渲染的时候
- 窗口尺寸发生变化
注意:回流一定会触发重绘,而重绘不一定会回流
5.3 浏览器优化机制
现在浏览器为了减少每次重排的开销,因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列
但是!当你获取布局信息的操作的时候,会强制队列刷新
- offsetTop、offsetLeft、offsetWidth、offsetHeight
- scrollTop、scrollLeft、scrollWidth、scrollHeight
- clientTop、clientLeft、clientWidth、clientHeight
- getComputedStyle()
- getBoundingClientRect
5.4 如何避免触发回流和重绘
css方面
- 避免使用table布局。
- 尽可能在DOM树的最末端改变class。
- 避免设置多层内联样式。
- 将复杂的动画效果应用到position属性为absolute或fixed的元素上 使其脱离文档流,避免多次回流
- 避免使用CSS表达式(例如:calc())
- CSS3硬件加速(GPU加速)transform/opacity/filters/will-change
- 可以给动画加z-index提升渲染性能
js方面
- 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性
- 避免频繁操作DOM,克隆一个元素,在它上面应用所有DOM操作,最后再把它添加到文档中 cloneNode replaceNode
- 也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘
- 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来
5.5 GPU加速
transform/opacity/filters 会触发GPU加速,创建一个独立的复合图层
transform/opacity/filters,<video>/<canvas>/z-index都会创建独立的符合图层
过多开启的弊端
- GPU加载大量的纹理会引起内存问题
- 使用GPU渲染会影响字体的抗锯齿效果。这是因为GPU和CPU具有不同的渲染机制。即使最终硬件加速停止了,文本还是会在动画期间显示得很模糊。
6. 一个TCP能发几个HTTP请求
- HTTP1.0每次发完一个请求即断开TCP连接,但可以头部connection:keep-alive可发送多条
- HTTP1.1支持长连接,只要TCP不断开可以连续发送,无上限
- HTTP2.0支持多用复用,支持并发多个和长连接
7. Token
7.1 token解决的问题
- 完全由应用端管理,避开了同源策略
- token可以避免csrf攻击
- 可以多服务器之间共享
7.2 如何解决token过期问题
- token发送给服务端,服务端缓存过期时间,每次请求都查看过期时间,如果过期则直接推迟过期时间
- 前端将token发送给服务端,服务端发现token过期提示前端,前端调用后端的refresh刷新过期时间
7.3 token组成
JWT格式:Header.Payload.Signature
Header = {
alg: "HS256", // 签名算法
typ: "JWT" // 令牌类型
}
Payload = { // 内容提
sub: '123123',
name: 'Jone',
admin: true,
}
Signature = Hash256(`${base64(header)}.${base64(patload)}.${secret}`)
7.4 分离认证服务
8.DNS
全称 Domain Name System ,即域名系统。万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。DNS协议运行在UDP协议之上,使用端口号53。
www.dnscache.com (域名) - DNS解析 -> 11.222.33.444 (IP地址)
8.1 DNS查询过程如下:
iOS设备请直接跳到第三步骤
-
首先搜索浏览器自身的DNS缓存,如果存在,则域名解析到此完成。
-
如果浏览器自身的缓存里面没有找到对应的条目,那么会尝试读取操作系统的hosts文件看是否存在对应的映射关系,如果存在,则域名解析到此完成。
-
如果本地Host文件中没有那么操作系统会把这个域名发送给这里设置的LocalDNS,也就是本地区的域名服务器。这个DNS通常都提供给你本地互联网接入的一个DNS解析服务。这个专门的域名解析服务器性能都会很好,它们一般都会缓存域名解析结果,当然缓存时间是受域名的失效时间控制的,一般缓存空间不是影响域名失效的主要因素。
-
如果本地DNS服务器还没找到的话,它就会向根服务器发出请求,进行递归查询。
-
根域名服务器返回给本地域名服务器一个所查询的域的主域名服务器(gTLD Server)地址。gTLD是国际顶级域名服务器,如.com,.cn、.org等。全球只有13台左右。
-
本地域名服务器(Local DNS Server)再向上一步返回的gTLD服务器发送请求。
-
接受请求的gTLD服务器查找并返回此域名对应的Name Server域名服务器的地址,这个Name Server通常就是你注册的域名服务器,例如你在某个域名服务提供商申请的域名,那么这个域名解析任务就由这个域名提供商的服务器来完成
-
Name Server域名服务器会查询存储的域名和IP的映射关系表,正常情况下都根据域名得到目标IP记录,连同一个TTL值返回给DNS Server域名服务器。
-
返回该域名对应的IP和TTL值,Local DNS Server会缓存这个域名和IP的对应关系,缓存的时间由TTL值控制。
-
返回该域名对应的IP和TTL值,Local DNS Server会缓存这个域名和IP的对应关系,缓存的时间由TTL值控制。
9. CDN
CDN,全称Content Delivery Network,根本的作用是将网站的内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容,提高用户访问网站的响应速度。他-有别于镜像,它比镜像更智能,可以这样做一个比喻:CDN=镜像(Mirror) + 缓存(cache) + 整体负载均衡(GSLB),因而,CDN可以明显提高Internet中信息流动的效率。目前CDN都以缓存网站中的静态数据为主,如CSS、JS、图片和静态网页等数据。用户在从主站服务器请求到动态内容后再从CDN上下载这些静态数据,从而加速网页数据内容的下载速度,如淘宝有90%以上的数据都是由CDN来提供的。这里引用一个网上比较形象的例子:A家的网速 100M的,但他只用了10M的速度,B家的网速是10M的,但是他需要15M的速度才行。怎么办呢。 C是一家CDN服务商,在A家有个节点(就像A是一个赞助商一样)B在C家买了CDN加速服务。当B的速度不够的时候,CDN加速就会选择有节余的节点来帮B,提高B的速度。这样B的速度就能达到或超过15M ,皆大欢喜。A没浪费,B速度有了,C赚了钱。 当C的节点在全国都有,非常多的时候。那么你用C家的CDN加速服务,你就会健步如飞了。
9.1 CDN工作流程
一个用户访问某个静态文件(如CSS),这个静态文件的域名假如是www.baidu.com,而这个域名最终会被指向CDN全局中CDN负载均衡服务器,再由这个负载均衡服务器来最终分配是哪个地方的访问用户,返回给离这个访问用户最近的CDN节点。之后用户就直接去这个CDN节点访问这个静态文件了,如果这个节点中请求的文件不存在,就会再回到源站去获取这个文件,然后再返回给用户。
9.2 负载均衡
一个用户访问某个静态文件(如CSS),这个静态文件的域名假如是www.baidu.com,而这个域名最终会被指向CDN全局中CDN负载均衡服务器,再由这个负载均衡服务器来最终分配是哪个地方的访问用户,返回给离这个访问用户最近的CDN节点。之后用户就直接去这个CDN节点访问这个静态文件了,如果这个节点中请求的文件不存在,就会再回到源站去获取这个文件,然后再返回给用户。
10. 浏览器缓存
10.1 缓存优点
- 减少冗余的数据传输
- 减少服务器的负担,大大提升了网站的性能
- 加快了客户端加载网页的速度
10.2 分类
10.2.1 强缓存
10.2.1.1 流程
-
客户端首次请求,服务端回应头部附带expires/Cache-Control
-
客户端缓存资源,二次请求直接在内存缓存查找,未找到则在磁盘缓存查找
10.2.1.2 问题
-
expires由于为绝对时间,服务器和客户端可能存在时间偏差,导致缓存发生混乱
-
Cache-Control优先级高于expires
10.2.2 协商缓存
Last-Modified --> If-Modified-Since
ETag --> If-None_match
10.2.2.1 Last-Modified流程
-
客户端首次请求,服务端回应头部附带Last-Modified:Date表示该资源的最后修改时间
-
客户端后续请求都会头部附带If-Modified-Since:Date,服务器通过比对最后修改时间
-
命中则返回304,否则返回资源并附带新的Last-Modified
10.2.2.2 ETag流程
-
客户端首次请求,服务端回应头部附带ETag:文件唯一标识符
-
客户端后续请求都会头部附带If-None-Match:文件唯一标识符
-
服务端对比标识符来判断是否文件发生了更改
-
命中回应304
10.2.2.3 问题
- 编辑了资源但资源内容未发生改变,也会被当做修改了,重新缓存
- 修改文件速度太快,if-modified-since只能识别1s以上的时间差