浏览器
浏览器缓存
强缓存
早期HTTP1.0
通过Expires字段,存在于浏览器返回的响应头中,告诉浏览器这个过程是可以直接从浏览器获取数据,无需再次请求。
1 | Expires: Wed, 22 Nov 2019 08:41:00 GMT |
但是由于服务器和浏览器时间可能并不一致,因此在HTTP1.1中这种操作被废弃了。
Cache-Control
区别于Expires的具体的过期时间,前者采用了过期时长来控制。
1 | Cache-Control:max-age=3600 |
还有其他参数
- private只有浏览器进行缓存
- no-cache跳过强缓存,直接进入协商缓存
- no-store不进行缓存
- s-maxage针对代理服务器的缓存时间
协商缓存
当强缓存失效后,浏览器在请求头中携带相应的缓存tag来向服务器发请求,由服务器根据这个tag,来决定是否使用缓存。
缓存tag:
Last-Modified最后修改时间
服务器在第一次响应后会在响应头添加这个字段,也就是服务器的最后修改时间,浏览器第二次请求会加上浏览器传过来的最后修改时间,若服务器端修改时间改变,则直接更新,返回新的资源。否则返回304,告诉浏览器直接使用缓存
ETag文件唯一标识
ETag是服务器根据当前文件内容给浏览器添加的唯一标识,第一次请求时,浏览器会将ETag直接放在响应头发送给浏览器,浏览器在下次请求后会将这个值作为If-None-Match
这个字段的内容,将其发送给服务器,服务器再进行对比,并决定浏览器是否使用缓存。
两者对比:
从精准度来将,ETag显然更高,而从性能来看,Last-Modifie显然更方便。
缓存存放的位置
按照优先级高低排列依次是:
Service Worker
借鉴了webworker的思路,让js运行在主线程之外,但是脱离了浏览器窗体,不能操纵DOM
Memory Cache
效率快,但存活时间短
Disk Cache
效率慢,但存活时间长
Push Cache
在HTTP2.0才更多的使用
总结:
浏览器本地存储
主要分为:
Cookie
Cookie最早设计出来仅仅是为了弥补HTTP状态管理上的不足
本质上就是在浏览器存储一个很小的文本文件(4KB)
但是Cookie有很多致命的缺陷:
- 容量缺陷(4K)
- 性能缺陷(Cookie紧跟域名,尽管该域名某些地址下不需要这些Cookie,请求都会携带上完整的Cookie,这个可以通过设置Cookie来配置)
- 安全缺陷(由于Cookie是以纯文本的形式在浏览器和服务器之间传递,因此很容易被非法劫持篡改,在Cookie有效期内重新发送给服务器,这是相当危险的。而且在HttpOnly为false的情况下,可以用js脚本直接获取Cookie)
webStorage
localStorage与Cookie相似,也会针对一个域名存储数据,但是与Cookie区别很大
- 容量上线是5M,而且是持久存储
- 只存在客户端,默认不参与服务端通信,避免了Cookie带来的性能问题和安全问题
- 接口封装
sessionStorage页面关闭就会消失
- 可以对表单信息进行维护
- 可以用来存储本次浏览记录,例如微博就是
IndexedDB
运行在浏览器的一个非关系型数据库,理论上它的容量没有上线
- 键值对存储
- 异步操作
- 受同源策略影响
输入浏览器到页面呈现发生了什么?
网络角度
(1)构建请求
1 | // 浏览器会构建请求行 |
(2)查找强缓存
先查找强缓存,若命中则直接使用,否则进入下一步
(3)DNS解析
由于输入的是域名,而数据包是通过IP地址传给对方的。因此我们需要得到域名对应的IP地址。也就是域名系统与IP的一个映射。
浏览器有DNS数据缓存的功能,即一个域名解析过,下次直接走缓存,不再需要DNS解析
(4)建立TCP连接
Chrome在同一域名下要求最多只能有6个TCP连接,超过的话剩下的请求就得等待
建立TCP连接需要经历下面三个阶段
- 三次握手建立客户端与服务器之间的连接
- 进行数据传输(接收方在接收到数据之后必须向发送方进行确认,如果发送方没接收到这个消息,则判断数据包丢失)
- 四次挥手断开连接
(5)发送HTTP请求
请求行+请求头+请求体
总结
解析算法
完成了网络请求个响应,如果响应头中Content-Type的值是text/html,那么接下来的就是浏览器的解析和渲染工作了。
渲染过程
在DOM树 → 布局树(layout tree)创建之后,浏览器还会创建图层树(layer tree)
一般情况下,节点的图层默认属于父亲节点的图层(这些图层也称为合成层),那么什么时候节点会提升到单独的图层(合成层)呢?
显示合成,如何产生合成层(形成单独的一层)
隐式合成,如何被动的形成合成层
当层级比较底的节点被提升为单独的图层之后,那么所有层级比他高的节点都会成为一个单独的图层。
层爆炸原理当一个z-index比较低的元素被提升为单独图层之后,层叠在他上面的元素统统会被提升为单独的图层,可能会增加上千个图层,大大增加内存压力!但是现在浏览器优化做的很好,已经很少存在层爆炸现象了!(层压缩)合成层的优缺点
优点:
- 合成层的位图会交给GPU合成,比CPU快,减轻CPU负担
- 需要repaint时,仅仅重绘本身,不会影响到其他图层
- transform 和 opacity 才不会触发 repaint,如果不是合成层,则其依然会触发 repaint。
缺点:
- 绘制的图层必须传输到 GPU,这些层的数量和大小达到一定量级后,可能会导致传输非常慢,进而导致一些低端和中端设备上出现闪烁;
- 隐式合成容易产生过量的合成层,每个合成层都占用额外的内存,而内存是移动设备上的宝贵资源,过多使用内存可能会导致浏览器崩溃,让性能优化适得其反。
重绘、回流、合成
重绘
触发条件
当DOM的修改导致样式的变化,并且没有影响几何属性的时候,会导致重绘
重绘过程
回流
触发条件
当对DOM结构的修改引发的DOM集合尺寸变化的时候,会发生回流
- 几何属性:width、height、padding、margin、left、top、border等
- DOM节点发生增删或移动
- 读写offset、scroll、client族属性时,浏览器为了获取这些值,会进行回流操作
- 调用window.getComputedStyle方法
回流过程
合成
有一种情况是直接合成,比如利用CSS3的transform、opacity、filter这些属性就可以实现合成的效果,也就是GPU加速。
在合成的情况下,会直接跳过布局和绘制的过程,直接进入非主线程处理的部分,即交给合成线程处理。
GPU善于进行图像处理
实践意义
- 避免频繁修改style,而是采用修改class的方式
- 使用createDocumentFragment进行批量的DOM操作
- 对于resize、sscroll等进行防抖节流处理
- 添加will-change:transform, 让渲染引擎为其单独实现一个图层
浏览器安全
XSS跨站脚本攻击(Cross Site Scripting)
指在浏览器中执行恶意脚本,从而拿到用户的信息并进行操作。浏览器没有对恶意代码进行过滤,使其在用户浏览器运行,从而:
- 窃取Cookie
- 监听用户行为,比如输入账号密码之后直接发送到黑客服务器
- 修改DOM伪造登录表单
- 在页面中生成悬浮广告
XSS也分为下面三种方式:
防范措施(一个信念,两个利用):
- 永远不要相信任何用户输入
- 利用Cookie的HttpOnly进制JS脚本获取Cookie
- 利用CSP规定浏览器只能访问特定资源
CSRF跨站请求伪造(Cross-site request forgery)
解决办法:
- 利用Cookie sameSite属性,对请求的Cookie携带进行限制
- 验证来源站点,通过请求头里面的Origin Referer
- CSRF Token , 例如Python Django框架,在请求的时候向服务器发送指定字符串,当再次发送请求时,客户端携带指定字符串,服务器经验证通过后,才命中请求。
中间人攻击
HTTPS为什么让数据传输更安全
由于HTTP明文传输,可能被截获、伪造请求,不会验证报文完整性
HTTPS的优点:
- 加密
- 完整性校验
- 身份认证
什么是TLS/SSL?
TLS(Transport Layer Security)
是 SSL(Secure Socket Layer)
的后续版本,它们是用于在互联网两台计算机之间用于身份验证
和加密
的一种协议。
TLS使用了对称加密和非对称加密两种
对称加密,一个密钥,如果密钥泄露,就完蛋了
非对称加密,一个公钥,一个私钥,即使公钥泄露,私钥依然保存在自己手中,没完蛋,但是是单向的,我传你,你不能传我
浏览器组成
- 浏览器主进程
- GPU进程
- 网络进程
- 多个渲染进程
- 多个插件进程
浏览器事件循环机制
执行栈
每一个函数在运行的时候都会生成新的执行上下文,执行上下文回包含当前函数的参数,局部变量信息,正在执行的上下文始终处于栈的顶部
任务队列
优化首屏加载时间
计算方式:performance.timing.domComplete - performance.timing.navigationStart
- 使用路由懒加载,只有在跳转到该路由时才加载组件
- 最好使用CDN的方式引入
- 采用HTTP缓存
- 按需加载组件
- 图片资源压缩
- gzip格式压缩