浏览器相关的内容一般都大家出去后,被问烂的问题,其中的内容多而杂,这边作一个统一的整理也给大家一些启发。
从URL输入到页面展示发生了什么
1.DNS域名解析(将域名解析成ip地址)
按以下顺序进行查找
- 浏览器缓存:浏览器会按一定频率去缓存dns
- 操作系统缓存:如果浏览器中找不到就去操作系统中找
- 路由缓存:路由器也有dns缓存
- ISP的dns服务器:isp(互联网提供商)有专门的服务应对dns查询
- 根服务器:向根服务器.com>.mi>www. 递归查询
2.tcp建立连接
三次握手
- 客户端发送SYN=1,seq=x 的数据包到服务器端
- 服务端发回一个SYN=1,ACK=X+1,seq=Y 传达确认信息
- 客户端传回一个ACK=Y+1,seq=z的数据包代表握手结束
3.发送http的请求
- 请求信息包含URL,协议版本,请求方法
请求方法含有:get,post,put,delete,patch,head,options,trace
put:请求会把文件放到服务器的固定路径里面(update操作)而post的文件让服务器自己放
head:请求只返回头信息,没有body
patch:类似put,用于创建更新资源(代表部分更新) option:用于url验证链接的服务器是否正常 - 请求头部分(附:http1.1增加了keepalive的tcp长连接)
- 请求体(入参)
4.服务器处理请求返回http报文
| 状态码 | 状态值 | 释义 | 类型 |
|---|---|---|---|
| 100 | continue | 继续 | |
| 200 | ok | 成功 | 请求成功 |
| 201 | create | 成功并创建资源 | 请求成功 |
| 202 | accepted | 接受请求没有处理 | 请求成功 |
| 301 | moved permanently | 永久重定向 | 重定向 |
| 302 | move temporarily | 临时重定向 | 重定向 |
| 303 | see other | 临时重定向并get新资源 | 重定向 |
| 304 | not modified | 没更新直接读取本地 | 重定向 |
| 400 | bad request | 错误请求 | 请求错误 |
| 401 | unauthonzed | 无权限 | 请求错误 |
| 403 | forbidden | 禁止访问 | 请求错误 |
| 404 | not found | 资源不存在 | 请求错误 |
| 500 | internal server error | 服务器错误 | 服务器错误 |
| 503 | service unavailable | 无法处理请求 | 服务器错误 |
- 响应头包含响应报文加信息,由键值对组成
- 响应体就是响应的返回数据
5.浏览器渲染页面
- 1.处理html,构建dom树(深度优先遍历->当前节点所有子节点然后再兄弟节点)
- 2.处理css,构建cssom树
- 3.dom和csson合并渲染树
- 4.根据渲染树,计算节点位置
- 5.调用gpu绘制,合成图层显示
6.断开连接(4次挥手)
- 1.浏览器发起报文 Fin,Ack,Seq,表示无数据传输
- 2.服务器发起报文 Ack,Seq,表示同意关闭
- 3.服务器发起报文 Fin,Ack,Seq,请求关闭
- 4.浏览器发起Ack,Seq,收到服务器报文后关闭,服务器等一段时间后无响应就关闭了
浏览器绘制和事件相关
图层
- 普通的文档流就是一个图层,特殊属性(position: fixed,translate3d的3d变换,video,iframe,动画实现的opacity等)可以生成一个图层
- 不同的图层渲染互不影响,所以频繁修改的内容放到单独一个图层中,但是过多的图层也会可能有反作用
重绘和回流
- 重绘:当节点更改外观,而不需要影响布局的时候,比如color
- 回流:布局或者几何属性需要修改
- 引起回流的方式:
1.改变window大小
2.改变字体
3.添加删除样式
4.文字改变
5.定位或者浮动
6.盒模型修改
减少重绘和回流
- 1.translate 代替top
- 2.visibility代替display:none
- 3.先把dom隐藏,再修改,如:display:none(重绘了1次),然后进行多次修改,再将其展示出来
- 4.不要使用table布局,小的改动就会重绘
- 5.动画速度过快就会回流,request.animationframe 可用这个函数代替
- 6.css选择符是从右到左查询的,避免过深
- 7.频繁运动的动画单独给个图层
Event Loop事件循环
js在执行过程中,会产生执行环境,这些执行环境会顺序的加入到执行栈中。执行栈中如果有异步代码,就会被挂起放到task中,一旦执行栈中的代码执行完毕结束就会从task队列中拿出需要执行的代码放入执行栈中。
- 微任务:process.nextTick,Promise,Object.observe,MutationObserver
- 宏任务:script,seTimeout,setInterval,setImmediate,I/O,UI rendering
- 浏览器是会先执行script中代码,因此不是所有微任务都比宏任务快
- 执行顺序如下:
1.执行同步代码,只是属于宏任务。
2.执行栈为空,查询是否有微任务要执行。
3.执行所有微任务。
4.如果有需要,执行ui渲染(后面会说ui渲染顺序)
5.执行宏任务中的异步代码,然后开始执行下一轮的Event Loop
UI渲染(浏览器的一帧中做的事情)
- 1.当Event Loop执行完microtasks之后会判断dom是否要更新,因为浏览器是60hz刷新率,所以每16ms会执行一次。
- 2.判断是否有resize或者scroll,如果有就触发,这俩个事件都是自带节流功能
- 3.判断是否触发了media.query
- 4.更新动画并发送事件
- 5.判断是否有全屏操作
- 6.执行request.AnimationFrame 回调(动画)
- 7.执行insterctionObserve回调(监听器)该方法判断元素是否可见(可用于懒加载,但是兼容不好)
- 8.更新界面
- 9.如果空闲就执行requestIdleCallback回调(在浏览器空闲时间中调度的函数排队,使得开发人员在主事件执行之后执行,而不影响延迟关键事件)
事件机制
事件触发有3个阶段
- 1.window往事件触发处传播遇到注册的捕获事件会触发
- 2.传播到事件触发处触发注册事件
- 3.从事件触发处往window传播,遇到注册的冒泡事件会触发
- 特殊情况:如果给同一个节点冒泡和捕获都给注册了,那么就按注册时候的先后顺序执行
注册事件
- addEventListener,有三个参数,第一个参数是是事件,第二个是触发函数,第三个可以是布尔值,可以是对象。如果boolean,就是useCapture,是否在捕获阶段触发。如果是对象有三个属性,capture(是否捕获阶段触发),once(boolean类型是否触发一次),passive(boolean类型表示永远不会调用preventDeafault)
- stopPropagation可以防止冒泡,stopImmediatePropagation可以防止冒泡还可以防止当前对象执行别的注册事件
页面性能优化
网络上的优化
- 1.DNS预解析
<link rel="dns-prefetch" href="//www.baidu.com" /> - 2.缓存
a.强缓存:Cache-control: max-age=30(单位是秒,http/1.1,优先级比expires高)
Expires: Wed, 22 Oct 2018 08:41:00 GMT(单位是时间,http/1.1)
b.协商缓存(服务端配置):
last-modified表示本地文件最后修改日期,If-Modified-Since 会将 Last-Modified 的值发送给服务器,询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来。
ETag 类似于文件指纹,If-None-Match 会将当前 ETag 发送给服务器,询问该资源 ETag 是否变动,有变动的话就将新的资源发送回来。并且 ETag 优先级比 Last-Modified 高。 - 3.使用http2.0
http1.1 一个tcp链接只能同时处理一个请求
http2.0 一个tcp链接可以处理多个请求 - 4.预加载和预渲染
标签中可以 as script,style,image,media,document
<link rel="preload" href="http://example.com" />
<link rel="prerender" href="http://example.com" />
渲染过程上
- 懒执行 ,懒加载
- 减少重绘和回流
文件优化
- 1.图片大小使用正确尺寸(图片服务器可控制尺寸)
- 2.base64小图
- 3.雪碧图
- 4.webworker 异步运行代码
- 5.cdn加载(同一个域名下2-6个并发请求)
跨域
jsonp
- 原理 就是利用
<script>标签没有跨域限制的漏洞。通过<script>标签指向一个需要访问的地址并提供一个回调函数来接收数据当需要通讯时。(只有get请求,没有post)
cors
- 需要前后端一起设置,服务器端需要Access-Control-Allow-Origin设置