1.事件机制
事件触发三阶段
- 从
window往事件触发处传播,如果遇到注册的捕获事件会触发 - 事件触发处的绑定事件会发生
- 从事件触发处往winodw传播,如果有冒泡事件则触发
但是如果一个节点同时注册了触发和捕获事件,又是事件触发处,按照顺序执行。
注册事件
EventTarget.addEventListener(type, listener, options)
- type代表事件类型,最典型的就是
click - listener 一般是一个函数,表示监听触发的事件
- options有好几个属性,capture表示正常的捕捉事件,每次都能触发;once只能触发一次,true会置false;passive表示回调函数永远不会preventDefault()
阻止事件
- stopImmediatePropagation 阻止绑定在该target上的其他事件发生,从此一个type只会触发这一个事件
- e.preventDefault() 阻止传播进来的事件的默认行为
- stopPropagation 阻止事件进一步冒泡传播,
事件代理
当一个节点是动态的时候,将事件绑定在其父节点上以节省内存,不用注销节点事件。
2.跨域
首先了解,浏览器有同源策略,即域名不同,端口不同,协议有一个不同就是跨域,AJAX请求会失败。主要是用于防御CSRF攻击(Cross site request forgy)跨站脚本攻击。
同域代理
向后端发送http请求,后端再根据请求携带的真实地址转发请求。
script img-scr--JSONP
这两个标签是允许跨域的,我们可以将scr指向脚本的地址并设置一个回调函数来接受数据,但是仅限于get请求
CORS
在CORS(Cross Origin Resource Sharing)出现之前同域代理和JSONP是跨域的主流解决方案。
CORS主要是利用HTTP1.1的特性,http header 里面有两个功能
- 允许或者组织浏览器向其他域名发送请求
- 用于接收还是拒绝其他域名返回的响应数据
正常的跨域请求是 浏览器发送请求,跨域服务器返回数据,但是浏览器不接受返回的响应数据。
在发送http响应请求的时候,会加上originheader向服务器表面这是一个跨域请求。
如果要允许跨域,需要服务器后端设置Access-Control-Allow-Origin。跨域请求有简单请求和复杂请求。简单请求仅限于 GET,HEAD,POST和Content-Type = text/plain 或者multipart/form-data。
如果响应请求没有这个header,那么浏览器就不会接收数据。
如果不是简单请求,那么浏览器会先发送一个OPTION请求,带上Access-Control-Request-Headers and Access-Control-Request-Method。如果响应数据http header里面没有Access-Control-Allow-Header/Method 或者对应的内容对不上,浏览器就不会发送正式请求。
还可以通过设置二级域名和使用postMessage解决跨域
3.浏览器缓存机制
一个请求可以分为三个阶段,网络请求,后端处理,浏览器响应。缓存可以帮助我们在第一和第三阶段优化性能。而缓存机制分为缓存位置和缓存策略
缓存位置
- Service Worker:SW并不是存储的位置而是说SW可以控制哪些内容是否缓存,缓存在哪
- Memory Cache: 页面上的部分的大内容都会被缓存进Memory Cache, 但是大文件或者内存利用率高的使用使用disk Cache
- Disk Cache: 将部分内容保存在Disk Cache
- Push Cache: 是HTTP2 协议支持的缓存地点,主要特点是可以支持多页面共用缓存,只在Session中存在 页面关闭立即消失
- 网络请求:以上缓存都没有命中,那么就会发送网络请求
缓存策略
Cache-Control 控制优先级
- no-store: 完全不使用缓存
- no-cache: 即使缓存命中也要发送到服务端验证
- public/private: 是否允许代理服务器缓存
- max-age 查看是否过期
- expires 是否过期
是否命中缓存流程
- 先检查是否过期(max-age, expire)
- 过期了进行协商缓存,没过期直接使用不发送请求
- 协商缓存先检查Etag,没有Etag检查 LastModified 都没有请求服务器(200)
- 有Etag 检查If-None-Match 相同请求返回304
- 有LastModified 检查If-Modified-Since 未改变返回304
- 有一个不通过请求数据返回200
频繁变动的资源
频繁变动的资源不应该使用固定缓存而是应该使用no-cache 配合Etag来检查是否需要新资源。不会减少请求次数但是可以减少数据请求的大小
4.浏览器渲染机制
HTML -> DOM tree
- 通过HTTP协议传输HTML的字节数据。
- 浏览器将字节数据转变为字符串
- 分析字符串,打上token
- 将每个token变成一个个NODE
- 使用tree结构将这些NODE连接起来
HTML 下面可以有HEAD,BODY这两个子树。HEAD下面可以有meta link之类的node BODY下面可以有p标签之类的NODE
CSS => CSSOM tree
与DOMtree是很相似的,CSS因为可以有子类选择器,也会有tree结构。而且CSS应该放在最前面引入,因为通过CSS可能要重新渲染一次页面,如果HTML先渲染然后CSS再来一次会浪费性能,不如一开始就引入CSS。
生成渲染树
浏览器会将DOMtree和CSSOMtree 合并成渲染树,只会渲染要显示的节点,如果某个节点是display:none那么就不会显示。
为什么操作DOM性能消耗大?
因为DOM是渲染引擎的东西,JS是JS引擎的东西。它们由两个线程控制在同一个进程中且这两个线程互斥,跨线程通信设计到线程的死锁,通信等操作,十分消耗资源。
经典面试题:插入几万个 DOM,如何实现页面不卡顿?
可以考虑使用懒加载和预加载的方式加载这些DOM,读入这些DOM但是display:none 只渲染在浏览器可视范围内的节点。
预加载就是display:none
懒加载需要几个API比如document.documentElement.clientHeight, document.querySelectorAll,加上监听scroll事件 其中需要一次性读入全部的DOM节点,这个操作可能不太能接受。
第二种方法是 虚拟滚动(vitural scroll)
什么情况会阻塞渲染?
HTML,CSS的渲染本身就是一种阻塞,JS的执行也会。除非加上defer属性 表示并行下载+最后执行。async属性表示 JS的下载和解析不会阻塞渲染。
重绘和回流
reflow一般是指渲染树上某个节点的几何形状改变或者页面布局改变。需要重新渲染页面 paint是指DOM元素节点的颜色 风格的改变,导致的重新渲染
回流必定重绘,反之不一定。回流成本比重绘高得多。
会导致性能问题的动作
- 改变盒模型
- 定位or浮动
- 改变文字/字体
- 添加/删除样式
- 改变window大小
几个小技巧
- visibility 代替 dispaly:none(注意业务场景,有时不能替换)
- top 代替 transform
- 尽量不使用table
- 不要再循环里面使用节点当变量
- 将多个DOM操作合并一起操作而不是逐条操作
关键渲染路径
在不考虑缓存和优化网络协议的情况下,怎么尽可能渲染页面?
- 从文件大小考虑: 压缩JS CSS HTML
- 从 script 标签使用上来考虑 defer async
- 从 CSS、HTML 的代码书写上来考虑: 避免过多的子结构
- 从需要下载的内容是否需要在首屏使用上来考虑 懒加载 预加载 虚拟滚动
网站从开启到加载的过程
- 预处理
- 查询DNS,返回IP
- 建立TCP连接
- 发送HTTP请求
- 等待响应数据
- 静态资源下载
- DOMtree CSSOM tree 合成 渲染树 然后渲染 执行JS
前端性能指标
- 白屏时间---等待响应
- 首屏时间---静态资源下载(主要是图片,最后图片加载时间-加载开始时间 = 首屏时间)
- 用户可操作---计算布局
- 页面总下载(还是图片,加载慢)---渲染完成
性能优化思路
- 减少数据请求次数
- 减小数据请求体积
- 加快请求速度?
- 缩短渲染时间/加载优化
- 代码性能优化
减少数据请求次数
主要是缓存的使用,通过对资源使用情况的分析配置缓存。如果资源不经常变,可以使用缓存并将过期时间加长。如果资源频繁变动,那么过期时间短或者no-cache,配合Etag来检查资源。后者的方法其实是减少数据请求体积,因为不能减少请求次数。 HTTP keep-alive
减小数据请求体积
- HTML,CSS,JS压缩
- accept-coding: gzip,
- 图片合并 雪碧图
- 使用合适的图片类型
加快请求速度
- CND--缩短服务器距离
- DNS缓存
代码性能优化
- CSS不要多级查询子结构
- HTML不要过多嵌套
- JS尽量不要直接操作DOM空间(尤其是循环中
- 避免使用arguments,debugger,使用扩展运算符代替arguments
缩短渲染时间
- CSS放开头,JS放最后
- 减少repaint,reflow
- 缓存也能缩短渲染时间
- 懒加载/快加载 滚动加载
- 避免302重定向
- 合理使用3D硬件加速