一个很是巨大的问题,涉及的领域好多……css
稍微理了下主干,固然不是我本身理的,综合了不少前辈的文章,列表以下:html
http://web.jobbole.com/94150/node
https://www.cnblogs.com/daijinxue/p/6640153.htmlweb
https://segmentfault.com/a/1190000006879700算法
https://segmentfault.com/a/1190000003925803apache
https://blog.csdn.net/u012194956/article/details/79110212json
从输入url到页面加载发生了什么
总览
- 浏览器地址栏输入URL并回车
- 浏览器查找当前URL是否存在缓存,并比较缓存是否过时
- DNS解析URL对应的IP
- 根据IP创建TCP链接(三次握手)
- 发送HTTP请求
- 服务器处理请求,浏览器接受HTTP响应
- 浏览器解析并渲染页面
- 关闭TCP链接(四次握手)
浏览器进程/线程模型,JS的运行机制
多进程的浏览器
浏览器是多进程的,可能包括:segmentfault
- 浏览器主进程:负责协调、主控,只有一个
- 浏览器渲染进程(内核):每一个Tab页面有一个互不影响的进程,负责页面渲染、脚本执行、事件处理等(有时候会优化,多个空白Tab会合并成一个进程)
- 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才建立
- GPU进程:最多一个,用于3D绘制
多线程的浏览器内核
每一个Tab的浏览器内核进程是多线程的,包括:浏览器
- GUI渲染线程
- JS引擎线程
- 事件触发线程
- 定时触发器线程
- 异步HTTP请求线程
JS引擎是浏览器内核进程中的一个单线程。缓存
解析URL
URL的几大部分:
- protocal 协议头:HTTP,HTTPS,FTP
- host 主机域名或IP地址
- port 端口号,http默认80,https默认443
- path 目录路径
- query 查询参数
- fragment #后的哈希值,通常用来定位到某个位置
HTTP与HTTPS
HTTP的缺点:
- 通讯使用明文,内容可能被窃听
- 不验证通讯方身份,可能遭遇假装
- 没法验证报文的完整性,有可能被篡改
HTTP+加密+认证+完整性保护=HTTPS
- HTTPS是身披SSL外壳的HTTP:一般状况下HTTP是直接和TCP层进行通讯的。当使用SSL(安全套接字)时,则演变成HTTP先和SSL通讯,SSL再和TCP通讯。

SSL
- 对称加密:加密和解密用同一个密钥,易被截取密钥
- 非对称加密(公开密钥加密):发送密文一方使用对方的共有密钥进行加密处理,对方收到加密信息后,再使用本身的私有密钥进行解密。
- HTTPS采用两者结合的方式,由于非对称加密相比对称加密处理速度较慢**,因此使用非对称加密传输对称加密的共享密钥,再使用共享密钥进行通讯。** -** 公开密钥的认证是要钱的**!私有密钥保存在服务器端。
SSL/TLS握手流程
1. 浏览器请求创建SSL连接,并向服务端发送一个随机数–Client random和客户端支持的加密方法,好比RSA加密,此时是明文传输。 2. 服务端从中选出一组加密算法与Hash算法,回复一个随机数–Server random,并将本身的身份信息以证书的形式发回给浏览器 (证书里包含了网站地址,非对称加密的公钥,以及证书颁发机构等信息) 3. 浏览器收到服务端的证书后 - 验证证书的合法性(颁发机构是否合法,证书中包含的网址是否和正在访问的同样),若是证书信任,则浏览器会显示一个小锁头,不然会有提示 - 用户接收证书后(无论信不信任),浏览会生产新的随机数–Premaster secret,而后证书中的公钥以及指定的加密方法加密`Premaster secret`,发送给服务器。 - 利用Client random、Server random和Premaster secret经过必定的算法生成HTTP连接数据传输的对称加密key-`session key` - 使用约定好的HASH算法计算握手消息,并使用生成的`session key`对消息进行加密,最后将以前生成的全部信息发送给服务端。 4. 服务端收到浏览器的回复 - 利用已知的加解密方式与本身的私钥进行解密,获取`Premaster secret` - 和浏览器相同规则生成`session key` - 使用`session key`解密浏览器发来的握手消息,并验证Hash是否与浏览器发来的一致 - 使用`session key`加密一段握手消息,发送给浏览器 5. 浏览器解密并计算握手消息的HASH,若是与服务端发来的HASH一致,此时握手过程结束,
以后全部的https通讯数据将由以前浏览器生成的session key并利用对称加密算法进行加密
HTTPS的好处
- SEO:搜索引擎排名更高
- 安全性:
- 使用https协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
- https协议是由SSL+http协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程当中不被窃取、改变,确保数据的完整性。
- https是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增长了中间人攻击的成本。
HTTPS的缺点
- 使页面加载时间延长50%,增长10%-20%的好点
- 影响缓存,郑家数据开销
- 加密范围有限,在黑客攻击、拒绝服务攻击、浏览器劫持方面没什么做用
- SSL整数的信用链体系并不安全
- 费用
- 握手协议费时
- 占用服务器资环高
浏览器缓存
强制缓存(不须要向浏览器发起请求)判断HTTP首部字段:cache-control,Expires。
- cache-control中的max-age保存一个相对时间。例如Cache-Control: max-age = 484200,表示浏览器收到文件后,缓存在484200s内均有效。
- Expires是一个绝对时间,即服务器时间。浏览器检查当前时间,若是还没到失效时间就直接使用缓存文件。可是该方法存在一个问题:服务器时间与客户端时间可能不一致。所以该字段已经不多使用。
- 若是同时存在cache-control和Expires,浏览器老是优先使用cache-control。
对比缓存(须要向服务器发送请求)经过HTTP的last-modified,Etag字段进行判断
-
last-modified是第一次请求资源时,服务器返回的字段,表示最后一次更新的时间。下一次浏览器请求资源时就发送if-modified-since字段。服务器用本地Last-modified时间与if-modified-since时间比较,若是不一致则认为缓存已过时并返回新资源给浏览器;若是时间一致则发送304状态码,让浏览器继续使用缓存。
-
Etag:资源的实体标识(哈希字符串),当资源内容更新时,Etag会改变。服务器会判断Etag是否发生变化,若是变化则返回新资源,不然返回304。 
DNS解析
经过域名查找目标文件所在主机的IP地址 查找过程: 查找过程
-
浏览器搜索本身的 DNS 缓存(维护一张域名与 IP 地址的对应表);
-
搜索操做系统中的 DNS 缓存(维护一张域名与 IP 地址的对应表);
-
搜索操做系统的 hosts 文件( Windows 环境下,维护一张域名与 IP 地址的对应表);
-
操做系统将域名发送至 LDNS**(本地区域名服务器**,若是你在学校接入互联网,则 LDNS 服务器就在学校,若是经过电信接入互联网,则 LDNS 服务器就在你当地的电信那里。)LDNS 查询 本身的 DNS 缓存(通常查找成功率在 80% 左右),查找成功则返回结果,失败则发起一个迭代 DNS 解析请求;
-
LDNS 向 Root Name Server (根域名服务器,其虽然没有每一个域名的的具体信息,但存储了负责每一个域,如 com、net、org等的解析的顶级域名服务器的地址)发起请求,此处,Root Name Server 返回 com 域的顶级域名服务器的地址;
-
LDNS 向 com 域的顶级域名服务器发起请求,返回 baidu.com 域名服务器地址;
-
LDNS 向baidu.com 域名服务器发起请求,获得 www.baidu.com 的 IP 地址;
-
LDNS 将获得的 IP 地址返回给操做系统,同时本身也将 IP 地址缓存起来;
-
操做系统将 IP 地址返回给浏览器,同时本身也将 IP 地址缓存起来;
-
至此,浏览器已经获得了域名对应的 IP 地址。
DNS优化
DNS缓存
NS存在着多级缓存,从离浏览器的距离排序的话,有如下几种: 浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。
DNS负载均衡
DNS能够返回一个合适的机器的IP给用户,例如能够根据每台机器的负载量,该机器离用户地理位置的距离等等,这种过程就是DNS负载均衡,又叫作DNS重定向。
TCP链接(三次握手)
上图部分标志说明:
(1)ACK:TCP规定,只有当ACK=1时有效,也规定链接创建后全部发送的报文的ACK必须为1
(2)SYN(SYNchronization):在链接创建时用来同步序号。当SYN=1而ACK=0时,代表这个是一个链接请求报文。对方若赞成创建链接,则响应报文中SYN=1,ACK=1。所以,SYN置1表示这是一个链接请求或链接接受报文。
(3)FIN(finish):终结的意思,用来释放一个链接。当FIN=1时,代表此报文段的发送方的数据已经发送完毕,并请求释放链接。
三次握手
(1)第一次握手:创建链接。客户端发送链接请求报文段,将SYN位置1,序列号seq(sequence number)为x;而后,客户端进入SYN_SEND状态,等待服务器的确认。
(2)第二次握手:服务器收到SYN报文段服务器收到客户端的SYN报文段,须要对这个SYN报文段进行确认,ACK位置1,确认号ack(acknowledgement number)为x+1;同时,本身还要发送SYN请求信息,将SYN位置1,序列号seq为y;服务器将上述SYN+ACK报文段一并发送给客户端,此时服务器进入SYN_RECV状态
(3)第三次握手:客户端收到服务器的SYN+ACK报文段:而后将确认号ack设置为y+1,向服务器发送ACK报文段。这个报文段发送完毕后,客户端和服务器都进入ESTABLISHED状态,完成TCP三次握手,以后能够开始传数据 !
HTTP请求
- HTTP请求报文是由三部分组成: 请求行, 请求报头和请求正文。
请求行
Method Request-URL HTTP-Version CRLF eg: GET index.html HTTP/1.1
- 经常使用的方法有: GET, POST, PUT, DELETE, OPTIONS, HEAD。
请求报头
- 请求报头容许客户端向服务器传递请求的附加信息和客户端自身的信息。
- 常见的请求报头有: Accept, Accept-Charset, Accept-Encoding, Accept-Language, Content-Type, Authorization, Cookie, User-Agent等。
- Accept用于指定客户端用于接受哪些类型的信息,Accept-Encoding与Accept相似,它用于指定接受的编码方式。Connection设置为Keep-alive用于告诉客户端本次HTTP请求结束以后并不须要关闭TCP链接,这样可使下次HTTP请求使用相同的TCP通道,节省TCP链接创建的时间。
请求正文
当使用POST, PUT等方法时,一般须要客户端向服务器传递数据。这些数据就储存在请求正文中。在请求包头中有一些与请求正文相关的信息,例如: 如今的Web应用一般采用Rest架构,请求的数据格式通常为json。这时就须要设置Content-Type: application/json。
五层因特尔协议栈
1.应用层(dns,http) DNS解析成IP并发送http请求
2.传输层(tcp,udp) 创建tcp链接(三次握手)
3.网络层(IP,ARP) IP寻址
4.数据链路层(PPP) 封装成帧
5.物理层(利用物理介质传输比特流) 物理传输(而后传输的时候经过双绞线,电磁波等各类介质) 从客户端发出http请求到服务器接收,中间会通过一系列的流程。
- 从应用层的发送http请求
- 到传输层经过三次握手创建tcp/ip链接
- 再到网络层的ip寻址
- 再到数据链路层的封装成帧
- 最后到物理层的利用物理介质传输。
- ISO七层模型:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
http1.0 1.1 2 的区别
长链接与链接
首先看tcp/ip层面的定义:
- 长链接:一个tcp/ip链接上能够连续发送多个数据包,在tcp链接保持期间,若是没有数据包发送,须要双方发检测包以维持此链接,通常须要本身作在线维持(相似于心跳包)
- 短链接:通讯双方有数据交互时,就创建一个tcp链接,数据发送完成后,则断开此tcp链接
http1.0,http1.1
- http1.0中,默认使用的是短链接,也就是说,浏览器没进行一次http操做,就创建一次链接,任务结束就中断链接,譬如每个静态资源请求时都是一个单独的链接
- http1.1起,默认使用长链接,使用长链接会有这一行Connection: keep-alive,在长链接的状况下,当一个网页打开完成后,客户端和服务端之间用于传输http的tcp链接不会关闭,若是客户端再次访问这个服务器的页面,会继续使用这一条已经创建的链接
- keep-alive不会永远保持,它有一个持续时间,通常在服务器中配置(如apache),另外长链接须要客户端和服务器都支持时才有效
HTTP2.0
HTTP2.0 与http1.1
- http1.1中,每请求一个资源,都是须要开启一个tcp/ip链接的,因此对应的结果是,每个资源对应一个tcp/ip请求,因为tcp/ip自己有并发数限制,因此当资源一多,速度就显著慢下来
- http2.0中,一个tcp/ip请求能够请求多个资源,也就是说,只要一次tcp/ip请求,就能够请求若干个资源,分割成更小的帧请求,速度明显提高。
HTTP2.0特性
- 多路复用(一个tcp/ip能够请求多个资源)
- 首部压缩(HTTP头部压缩,减小体积)
- 二进制分帧(在应用层和传输层之间增长二进制分帧层,改进传输性能,实现低延迟和高吞吐量)
- 服务端推送(服务端能够对客户端的一个请求发出多个响应,能够主动通知客户端)
- 请求优先级(若是流被赋予了优先级,它就会基于这个优先级来处理,由服务器决定须要多少资源来处理该请求。)
服务器处理请求并返回HTTP报文
通用头部(状态码)
Request Url: 请求的web服务器地址 Request Method: 请求方式 (Get、POST、OPTIONS、PUT、HEAD、DELETE、CONNECT、TRACE) Status Code: 请求的返回状态码,如200表明成功 Remote Address: 请求的远程服务器地址(会转为IP)
1xx:指示信息–表示请求已接收,继续处理。
2xx:成功–表示请求已被成功接收、理解、接受。
3xx:重定向–要完成请求必须进行更进一步的操做。
4xx:客户端错误–请求有语法错误或请求没法实现。
5xx:服务器端错误–服务器未能实现合法的请求。
- 平时遇到比较常见的状态码有:200, 204, 301, 302, 304, 400, 401, 403, 404, 422, 500(分别表示什么请自行查找)。
响应报头,响应报文
- 常见的响应报头字段有: Server, Connection...。
- 服务器返回给浏览器的文本信息,一般HTML, CSS, JS, 图片等文件就放在这一部分。
cookie session

浏览器获取html,解析,渲染
过程以下
- 解析HTML,生成DOM树
- 解析CSS,生成CSS规则树
- 合并CSS和DOM数,生成render树
- 布局render树(layout/reflow),负责各元素尺寸、位置的计算
- 绘制render树(paint),绘制页面像素信息
- 浏览器将各层信息发送给GPU,GPU将各层合成,显示在屏幕上

HTML解析,构建DOM
- Bytes → characters → tokens → nodes → DOM
-
Conversion转换:浏览器将得到的HTML内容(Bytes)基于他的编码转换为单个字符
-
Tokenizing分词:浏览器按照HTML规范标准将这些字符转换为不一样的标记token。每一个token都有本身独特的含义以及规则集
-
Lexing词法分析:分词的结果是获得一堆的token,此时把他们转换为对象,这些对象分别定义他们的属性和规则
-
DOM构建:由于HTML标记定义的就是不一样标签之间的关系,这个关系就像是一个树形结构同样 例如:body对象的父节点就是HTML对象,而后段略p对象的父节点就是body对象
生成CSSOM树
过程同上
构建渲染树

渲染

-
计算CSS样式
-
构建渲染树
-
布局(回流,Layout,Reflow),主要定位坐标和大小,是否换行,各类position overflow z-index属性
-
绘制(重绘,Repaint),将图像绘制出来
回流与重绘
- Layout,也称为Reflow,即回流。通常意味着元素的内容、结构、位置或尺寸发生了变化,须要从新计算样式和渲染树
- Repaint,即重绘。意味着元素发生的改变只是影响了元素的一些外观之类的时候(例如,背景色,边框颜色,文字颜色等),此时只须要应用新样式绘制这个元素就能够了
什么会引发回流
1.页面渲染初始化
2.DOM结构改变,好比删除了某个节点
3.render树变化,好比减小了padding
4.窗口resize
5.最复杂的一种:获取某些属性,引起回流, 不少浏览器会对回流作优化,会等到数量足够时作一次批处理回流, 可是除了render树的直接变化,当获取一些属性时,浏览器为了得到正确的值也会触发回流,这样使得浏览器优化无效,包括 (1)offset(Top/Left/Width/Height) (2) scroll(Top/Left/Width/Height) (3) cilent(Top/Left/Width/Height) (4) width,height (5) 调用了getComputedStyle()或者IE的currentStyle
- 元素几何属性变化,margin,padding,height,width,border
优化方案
- 减小逐项更改样式,最好一次性更改style,或者将样式定义为class并一次性更新
- 避免循环操做dom,建立一个documentFragment或div,在它上面应用全部DOM操做,最后再把它添加到window.document
- (1)DocumentFragment 节点不属于文档树,继承的 parentNode 属性老是 null。不过它有一种特殊的行为,该行为使得它很是有用,即当请求把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的全部子孙节点。这使得 DocumentFragment 成了有用的占位符,暂时存放那些一次插入文档的节点。它还有利于实现文档的剪切、复制和粘贴操做。其实他就是一个游离在DOM树外面的容器,因此你在把它插入文档节点以前,随便给他增删节点都不会引发回流
- (2)使用display:none,只引起两次回流和重绘。道理跟上面的同样。由于display:none的元素不会出如今render树
- (3)使用cloneNode和replaceChild技术,引起一次回流和重绘(这条其实没太明白)
- 避免屡次读取offset等属性。没法避免则将它们缓存到变量
- 将复杂的元素绝对定位或固定定位,使得它脱离文档流,不然回流代价会很高
- 尽可能不要使用表格布局,若是没有定宽表格一列的宽度由最宽的一列决定,那么极可能在最后一行的宽度超出以前的列宽,引发总体回流形成table可能须要屡次计算才能肯定好其在渲染树中节点的属性,一般要花3倍于同等元素的时间。
资源外链的下载
遇到外链时的处理
- 遇到外链时,会单独开启一个下载线程去下载资源(http1.1中是每个资源的下载都要开启一个http请求,对应一个tcp/ip连接)
遇到CSS样式资源
CSS资源的处理有几个特色:
- CSS下载时异步,不会阻塞浏览器构建DOM树
- 会阻塞渲染,也就是在构建render时,会等到css下载解析完毕后才进行(这点与浏览器优化有关,防止css规则不断改变,避免了重复的构建)
- media query声明的CSS是不会阻塞渲染的
遇到JS脚本资源
JS脚本资源的处理有几个特色:
- 阻塞浏览器的解析,也就是说发现一个外链脚本时,需等待脚本下载完成并执行后才会继续解析HTML
- 浏览器的优化,通常现代浏览器有优化,在脚本阻塞时,也会继续下载其它资源(固然有并发上限),可是虽然脚本能够并行下载,解析过程仍然是阻塞的,也就是说必须这个脚本执行完毕后才会接下来的解析,并行下载只是一种优化而已
- defer与async,普通的脚本是会阻塞浏览器解析的,可是能够加上defer或async属性,这样脚本就变成异步了,能够等到解析完毕后再执行 详见异步加载JS
遇到img图片类资源
- 遇到图片等资源时,直接就是异步下载,不会阻塞解析,下载完毕后直接用图片替换原有src的地方
loaded和domcontentloaded
简单的对比:
- DOMContentLoaded: 事件触发时,仅当DOM加载完成,不包括样式表,图片(譬如若是有async加载的脚本就不必定完成)
- load: 事件触发时,页面上全部的DOM,样式表,脚本,图片都已经加载完成了
怎么提升CSS加载速度?
- 使用CDN
- 将CSS压缩
- 合理使用缓存
- 减小HTTP请求数,多个CSS合并
JS引擎解析过程
JS的解释阶段
- JS是解释型语音,因此它无需提早编译,而是由解释器实时运行
- 核心的JIT编译器将源码编译成机器码运行
JS的预处理阶段
JS的执行阶段
- 执行上下文,执行堆栈概念(如全局上下文,当前活动上下文)
- VO(变量对象)和AO(活动对象)
- 做用域链
- this机制等
断开TCP链接(四次挥手)

- 第一次挥手是浏览器发完数据后,发送FIN请求断开链接。
- 第二次挥手是服务器发送ACK表示赞成,若是在这一次服务器也发送FIN请求断开链接彷佛也没有不妥,但考虑到服务器可能还有数据要发送,因此服务器发送FIN应该放在第三次挥手中。
- 这样浏览器须要返回ACK表示赞成,也就是第四次挥手
注:
-
为何服务器在接到断开请求时不当即赞成断开:当服务器收到断开链接的请求时,可能仍然有数据未发送完毕,全部服务器先发送确认信号,等全部数据发送完毕后再赞成断开。
-
第四次握手后,主机发送确认信号后并无当即断开链接,而是等待了 2 个报文传送周期,缘由是:若是第四次握手的确认信息丢失,服务器将会从新发送第三次握手的断开链接的信号,而服务器发觉丢包与从新发送的断开链接到达主机的时间正好为 2 个报文传输周期。