一、整个流程

1、当打开一个空白标签页时,浏览器主线程接管,会新创建一个Renderer进程,输入URL按回车,浏览器会开辟一个网络请求线程用于网络请求。
2、进行DNS域名解析IP寻址(解析、迭代过程)
3、建立TCP连接(三次握手)
4、发送HTTP请求,服务器端处理、响应请求,返回资源(HTML、CSS、JS)
5、将资源转交给Renderer进程管理
6、Renderer进程开始解析HTML和CSS,生成DOM树和CSSOM树,两者同时进行
7、解析过程中如果遇到script、img、link等标签时,浏览器会去下载这些内容。如果有缓存可以使用则使用缓存,否则去重新下载。
8、DOM树和CSSOM树生成后,开始生成render tree
9、浏览器Renderer进程进行布局render树(layout),计算节点位置、尺寸,在内存上生成Bitmap。
10、浏览器主线程进行绘制render树,绘制像素信息
11、断开TCP连接(四次挥手)

二、具体细节

1、浏览器

来自: https://zhuanlan.zhihu.com/p/45942094

多进程的浏览器:

进程 功能
Browser进程 对标签页协调主控、网络请求、绘制Bitmap到界面上
GPU进程 最多只有一个,用于3D绘制
插件进程 每种插件对应一个进程,仅当使用该插件时才创建该进程
Renderer进程 浏览器内核进程,每个标签页都有一个Renderer进程,负责每个标签页的页面渲染(在内存中生成Bitmap)、脚本执行、事件处理、定时器、异步HTTP请求

多线程的浏览器内核:

  1. GUI渲染线程:负责解析HTML和CSS,生成DOM树和CSSOM树,并合并成render树,布局渲染,在内存中生成Bitmap(位图),处理回流(reflow)和重绘(repaint);
  2. JavaScript引擎线程:负责执行JavaScript脚本(JavaScript是单线程语言就是指js引擎线程);
  3. 事件触发线程:用于控制事件循环。当事件条件被触发后将该事件添加到事件队列尾部,等待js引擎线程处理;
  4. 定时器触发线程:seiTimeout和setInterval所在的线程,当定时器触发计时结束后将要处理的逻辑放在事件队列尾部;
  5. 异步HTTP请求线程:进行AJAX请求,检测到状态变化时(status或readyState),如果有回调函数,产生状态变换事件,则将回调函数放在事件队列尾部。

注意GUI渲染线程和JavaScript引擎线程是互斥的。当JS引擎线程执行时,GUI渲染线程会被挂起,GUI更新会被添加到事件队列尾部,等JS引擎线程空闲时执行。所以如果JS引擎线程执行时间过长可能会发生阻塞,导致渲染不连贯。

JS的执行原理:
JS的解析是由JavaScript引擎线程进行的,是单线程的,所以各个任务需要排队进行。但由于有些任务耗时很久,如IO读写,如果一直等待会体验很差。所以需要某种机制来使得后面的任务能够先进行,就将任务分为同步任务和异步任务。同步任务可以按照顺序在js引擎主线程上执行,异步任务当条件满足时会被放在任务队列上。同步任务在主线程上执行时形成执行栈,异步任务有了运行结果后会将事件放在任务队列中。脚本运行时先执行任务栈里的任务,然后去任务队列中提取事件执行,不断循环,形成了JS的事件循环。

JS引擎解析过程:

JS解释阶段:

  1. 读取代码,进行词法分析(Lexical Analysis),将代码分解为词元(Token)
  2. 对词元语法分析(parsing),将词元整理为语法树(syntax tree)
  3. 使用翻译器翻译为字节码(bytecode)
  4. 使用字节码解释器解释为机器码

一般采用即时编译(JIT),字节码在运行到该行时进行编译,并进行缓存。
chrome V8省略了翻译步骤,直接转为机器码。

JS解释阶段主要就是JIT编译器将源码编译成机器码运行。

JS预处理阶段:

分号补全:
当有换行符(包括含有换行符的多行注释),并且下一个token没法跟前面的语法匹配时,会自动补分号。
当有}时,如果缺少分号,会补分号。
程序源代码结束时,如果缺少分号,会补分号。

function b() {return{a: 'a'};
}

由于分号补全,会变成:

function b() {return;{a: 'a'};
}

所以运行后是undefined

变量提升:包括函数提升和变量提升。

JS执行阶段:
见另一篇

JS垃圾回收阶段:
见另一篇

2、DNS域名解析

来自: https://www.jianshu.com/p/a5f26487f097

  • 在浏览器输入网址后需要进行域名解析,解析URL的协议名、域名、端口号、路径、查询参数(?)、哈希值(#)等 。因为通过域名是无法直接找到服务器的,需要将域名解析成IP地址,才能找到服务器。域名是为了便于理解和记忆设置的。
    输入网址后敲回车,首先会进行缓存的查找,如果找不到才会向DNS服务器发出请求

DNS缓存

DNS缓存由近至远可排序为:

浏览器缓存->系统缓存->路由器缓存->ISP服务器缓存->根域名服务器缓存->顶级域名服务器缓存->主域名服务器缓存。

1. 浏览器缓存:浏览器会按照一定频率缓存DNS记录。
2. 系统缓存:如果浏览器中没有找到,会在操作系统中找。(C:\Windows\System32\drivers\etc\hosts

3. 路由器缓存:路由器中也会有DNS缓存。

4. ISP服务器缓存:ISP(Internet Service Provider 互联网服务提供商)会有专门的DNS服务器来应对DNS查询请求。

5. 根服务器缓存:在根服务器中进行递归查询或者迭代查询

DNS解析

DNS解析过程如下:

  1. 输入www.google.com
  2. 本地域名服务器查找是否有缓存,没有的话去找根域名服务器
  3. 根域名服务器查找是否有缓存,没有的话本地域名服务器去找COM顶级域名服务器
  4. COM顶级域名服务器查找是否有缓存,没有的话本地域名服务器去找google.com域名服务器
  5. google.com域名服务器找到IP,返回IP给本地服务器
  6. 本地服务器将IP地址告诉浏览器
  7. 本地服务器还会将这个IP地址缓存,方便下一次访问(**缓存到哪里?? **)

解析过程为:.->.com.->google.com.->www.google.com.

DNS优化

  1. DNS缓存
  2. DNS负载均衡:(DNS重定向)对于某个网站配备多个IP地址,DNS服务器在解析域名时,会根据服务器负载量、距离用户距离等返回不同的IP地址,将客户端的访问引导到不同的服务器上,达到负载均衡。

CDN(Content Delivery Network)内容分发网络就是利用DNS重定向来为用户返回距离最近的IP地址,响应需求。

  1. DNS Prefetch预解析技术。在网页加载时,会为网页内的链接进行解析缓存,这样在点击时就无需进行域名解析,提高体验。

TCP和UDP

来自:https://www.cnblogs.com/xiaohuochai/p/9193083.html#anchor1

TCP和UDP的对比:

TCP UDP
面向连接 无连接
可靠 不可靠
一对一 一对一、一对多、多对多

TCP:

TCP将应用层报文封装成报文段,给每个报文段添加20字节的首部,包括了源端口、目的端口、序列号、确认号、窗口大小、校验和等等。经过封装的报文段从本地某个随机端口发送到服务器对应的端口(HTTP为80端口,HTTPS为443端口)。

TCP是可靠的传输,因为会对传输的数据进行确认,对未确认的数据进行重传,对于接受的数据按照正确的顺序进行排序,删除重复数据,提供拥塞控制。

TCP是面向连接的传输,在传输数据之前要进行三次握手。三次握手的过程中,双方都确认了自己能够收发。

1、主机A发起请求,发往主机B,发送初始序列号X,同步位SYN为1。
2、主机B收到信号后,发往主机A,发送初始序号Y,同步位SYN为1,同时确认位置为1,发送确认号X+1.
2、主机A收到信号后,发往主机B,发送序号X+1,确认位为1,确认序号Y+1。

主机A通过收到主机B的信号,确认了自己能收发,主机B通过主机A的两次信息,知道自己受到了信号,并且自己的信号也被接受了。

为什么不是两次握手?
防止发送的失效的连接请求突然传送到服务端,产生错误。
比如客户端发出一个请求,但由于网络滞留延误了,服务器端以为是一个新的连接请求,会发出确认,假如只有两次握手,那连接已经建立了,但客户端并没有法出请求,所以也不会理会确认。服务器端还在等待发送消息,浪费了很多资源。

TCP断开连接要进行四次挥手。因为TCP是全双工的,需要确认双方都不再收发。

补充:

  • 表示层:主要处理两个通信系统中交换信息的表示方式,包括数据格式交换,数据加密与解密,数据压缩与终端类型转换等。
  • 会话层:它具体管理不同用户和进程之间的对话,如控制登陆和注销过程。
  • 网络层通过IP协议进行路由。网络层收到传输层的数据段后,封装成数据包,添加上添加上源IP地址和目的IP地址,并且进行转发和路由
  • 数据链路层进行网络节点间的有效通信。数据链路层将数据包封装成,包括帧头和帧尾,帧头为源MAC地址和目的MAC地址,帧尾加上循环冗余校验,一旦出错就重传。
  • 物理层将数据帧转换为比特流,通过网卡发送出去,用电信号、光信号、微波等进行传输。

浏览器发送请求报文前

HTTP和HTTPS

来自: https://segmentfault.com/a/1190000006879700

HTTP

HTTP请求

HTTP请求即构建HTTP请求报文,通过TCP协议发送到服务器对应的端口(HTTP协议为80端口或8080端口,HTTPS为443端口)。
HTTP请求报文包括请求行、请求头、请求空行、请求正文

请求行
包括请求方式、URL、协议版本
如:GET index.html HTTP/1.1
常见的请求方式有:POST、GET、PUT、HEAD、OPTIONS、DELETE等

GET和POST的区别:

来自: https://www.zhihu.com/question/28586791

  1. GET会产生一个数据包,POST会产生两个。GRT发送请求时,把headers和data一起发送回去,服务器端响应200。POST先把headers发送出去,服务器端响应100 continue,浏览器再发送data,服务器响应200.

HTTP最早是作为与服务器交互HTML和表单的通讯协议,后来被广泛用到各种接口格式的定义上。
讨论POST和GET时,也要根据时浏览器使用的GET/POST还是HTTP作为接口传输协议的场景。

浏览器使用的GET和POST

  • 非Ajax的HTTP请求,即从浏览器和HTML诞生时就使用的GET/POST。
    浏览器用GET来获取HTML/CSS/JS/图片等资源,用POST提交< form >表单,并得到一个结果的网页。

GET

  • 用于读取一个资源。
  • 是幂等的,多次请求、读取对访问的数据不产生影响。
  • 本身是读取,可缓存。可到浏览器上(max-age),服务器上(Etag,可以减少带宽消耗)判断缓存。
  • 可保存为书签。
  • 数据格式上,由于GET请求一般都是通过url来触发的,要么是通过在地址栏输入,要么是点击了< a >中href的url,想要附加一些参数只能在url上附带querystring。HTTP协议本身没有这个限制。

POST

  • < form >标签定义一个表单,点击submit元素会发出POST请 求让服务器做一个操作。
  • 是不幂等的,每次操作都会产生影响。
  • 不可缓存,比如下订单,不经过服务器直接返回本地的下单成功,实际上服务器并没有接收到改变。
  • 不可保存为书签,否则每次点击都会再次操作。
  • 数据格式上,浏览器通过提交表单发出POST请求,会将表单里的数据编码到body里。body主要有两种格式:application/x-www-form-urlencoded和multipart/form-data,前者主要用于传递简单数据,如"key1=value1&key2=value2",后者用于上传文件,因为前者的编码方式对于文件很低效。浏览器在POST一个表单时,也可以在url上带参数,< form action=url" >中带参数即可。

接口中的GET和POST

  • 指通过如Ajax api、postman等工具发出的HTTP请求,此时就没有那么多限制了,只要符合HTTP协议规范就可以。
  • 参数可以放在url的querystring里、header里、body里,但这样的话每次都要讨论确定规范,预实就有了一些接口规范,如REST,充分运用GET、POST、PUT、DELETE,约定分别为查、增、改、删。
  • 请求体推荐使用json格式,相对于x-www-form-urlencoded,json能够发送的数据1)可以有嵌套结构;2)可以支持更丰富的数据类型加粗样式。但如果是上传文件,还是推荐使用multipart/form-data格式。

REST GET

  • 用于获取资源或资源列表
  • 可缓存
  • 相对来说更不安全。在url里面传递数据。但HTTP是明文协议,所以不管在哪里传递其实都能被看到。如果想要避免数据被窃取,需要采用HTTPS,用SSL协议进行加密。
  • 由于参数一般写在url中,url只支持ASCII码的某些子集,如某些字母、数字和特殊符号能直接不经过编码用于URL,其他内容需要经过编码。采用的编码方式比较混论,UTF-8、操作系统默认编码(GB2312)、网页的编码方式。
  • 请求数量:一般只有一个数据包,包含请求头和请求体。
  • 长度:主要是由于URL长度限制,有的最长2kb,与浏览器的限制有关。

REST POST

  • 作用:用于创建一个资源
  • 安全性:相对来说安全一点,在请求体里传数据。但HTTP是明文协议,所以不管在哪里传递其实都能被看到。如果想要避免数据被窃取,需要采用HTTPS,用SSL协议进行加密。
  • 编码参数写在body中,body能支持各种binary。用Content-Type来进行定义body的格式(application/x-www-form-urlencoded)和字符编码(UTF-8)。
  • 请求数量:由于请求头中一般都会携带控制类信息,具体的数据在请求体里,服务器解析时总是先解析全部的请求头部,了解控制信息后决定怎么进一步处理,是拒绝,还是根据content-type调用相应的解析器。客户端会进行一些优化,比如利用HTTP的Continued协议,客户端先发送所有请求头给服务器进行校验,如果通过,服务端返回100continue,客户端再传输剩下数据。如果请求被拒绝直接返回400之类的错误,交互就终止了。可以避免浪费带宽。但如果数据较小,就可以一次性全发过去,取决于浏览器各自不同的方案。
  • 长度:理论上没有限制,但也会做出一系列规定,可能跟服务器处理的能力有关。

顺便说一句,尽管在浏览器地址栏可以看到中文。但这种url在发送请求过程中,浏览器会把中文用字符编码+Percent Encode翻译为真正的url,再发给服务器。浏览器地址栏里的中文只是想让用户体验好些而已。

REST PUT

  • 用于替换一个资源,请求体应该是完整的资源。

使用PUT还是POST主要看是不是提前知道资源的所有数据,尤其是ID。当像上传一个新资源时,如AWS S3这样的对象存储服务,id就是ObjectName,用PUT即可;如果id时服务端自动生成的,用POST更合适。

现实中还有REST的变体,也可能用非REST的协议(比如JSON-RPC、SOAP等)。

请求头
包括了客户端要发给服务器的信息以及客户端自己的信息。
如:

Accept: 接收类型,表示浏览器支持的MIME类型
(对标服务端返回的Content-Type)
Content-Type:客户端发送出去实体内容的类型
Accept-Encoding:浏览器支持的压缩类型,如gzip等,超出类型不能接收
Accept-Language:
Cache-Control: 指定请求和响应遵循的缓存机制,如no-cache
Expires:缓存控制,在这个时间内不会请求,直接使用缓存,http`1.0`,而且是服务端时间
Max-age:代表资源在本地缓存多少秒,有效时间内不会请求,而是使用缓存,http`1.1`中
If-Modified-Since:对应服务端的Last-Modified,用来匹配看文件是否变动,只能精确到1s之内,http`1.0`中
If-None-Match:对应服务端的ETag,用来匹配文件内容是否改变(非常精确),http`1.1`中
Cookie: 有cookie并且同域访问时会自动带上
Connection: 当浏览器与服务器通信时对于长连接如何进行处理,如keep-alive。如果为keep-alive表明HTTP请求后不需要关闭TCP连接,下次TCP请求时可以使用相同的TCP通道,节省建立连接需要的时间。
Host:请求的服务器URL
Origin:最初的请求是从哪里发起的(只会精确到端口),Origin比Referer更尊重隐私
Referer:该页面的来源URL(适用于所有类型的请求,会精确到详细页面地址,csrf拦截常用到这个字段)
User-Agent:用户客户端的一些必要信息,如UA头部等
Accept:image/gif.image/jpeg.*/*
Accept-Language:zh-cn
Connection:Keep-Alive
Host:localhost
User-Agent:Mozila/4.0(compatible:MSIE5.01:Windows NT5.0)
Accept-Encoding:gzip,deflate.

请求空行
请求正文
当请求方式为POST或者PUT时,客户端会向服务器传递一些数据,此时的数据就存储在请求正文中。请求报文中有部分内容也是和请求正文相关的,如
比如:请求正文中可以放参数的序列化格式,表单对象,现在一般的接口请求中请求实体中是信息的json格式,而页面请求里面直接就是放一个HTML字符串。
Content-Type规定了请求的数据格式。
当请求的数据格式为json时,设置Content-Type:application/json。

username=jinqiao&password=1234
强缓存和协商缓存

当我们打开页面时就会加载资源(css,js,img),然后浏览器就会缓存这些资源文件,下次再次加载到相同资源时,就会先查看本地有没有缓存。

强缓存(200 from cache):浏览器判断本地缓存未过期不发起HTTP请求,直接使用本地缓存。(未过期时只能更新资源路径才能使得强缓存无效,相当于是另一个资源了)
协商缓存(304):浏览器发起HTTP请求服务端判断文件是否改变,如果没有改变会返回304,浏览器直接使用本地缓存。如果改变则返回200和资源。(ctrl+F5可以使协商缓存无效)

< META HTTP-EQUIV="Pragma" CONTENT="no-cache" >
设置no-cache也可以使得强缓存失效

缓存头部:

强缓存

(HTTP1.0)Expires/Pragma
(HTTP1.1)Cache-Control:Max-Age

为了向下兼容,仅使用max-age是不够的。

Pragma:no-cache,不可缓存
Expires:服务端配置,设置了绝对的过期时间(GMT格式),在这个时间前浏览器不会发出请求,而是直接使用本地缓存。
有两种时间:相对文件的最后访问时间(ATime)绝对修改时间(MTime)。
但是对应的是服务端时间,所以存在服务端时间可能与客户端时间不一致的问题,可能导致本地缓存无用

Cache-Control:服务端配置,可以取值Max-Age或No-Cache。如Cache-Control: max-age=3600。
设置了文档被访问后的存活时间相对的是文档第一次被请求时服务器记录的Request_time。在这个时间内浏览器不会发出请求,而是直接使用本地缓存。

两者同时存在时,Cache-Control优先。

协商缓存

(HTTP1.0)If-Modified-Since/Last-Modified
(HTTP1.1)If-None-Match/E-tag

If-Modified-Since/Last-Modified:记录文件最后修改时间
只能精确到1s;而且服务端文件可能会周期性发生改变,导致缓存失效。

If-None-Match/E-tag:一种指纹机制,只要文件改变就会变化。

两者同时存在时,If-None-Match/E-tag优先。

HTTPS

HTTP协议是基于TCP传输层协议的,HTTP报文包裹在TCP报文中进行传输,浏览器接收到TCP报文后会解包提取出HTTP报文。但这个过程中存在一定风险,因为HTTP报文是明文,如果中间被截取有信息泄露的风险。
HTTPS协议就是对HTTP进行加密,HTTPS的本质是HTTP+SSL或TLS,在HTTP报文被打包成TCP报文之前用SSL对报文进行加密。可以看到,在网络层级结构中,SSL和TLS在HTTP协议和TCP协议之间。


HTTPS在传输数据之前需要进行握手(SSL握手),这个过程中客户端和服务器会确立双方加密传输的密码信息。SSL/TLS使用对称加密和非对称加密混合,还有hash等。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与HTTP对比,提供了安全保证,但是由于握手和加密过程,时间上会损耗更大,所以是否选择HTTPS需要在安全和性能间做出权衡。

HTTP1.0采用一次请求-响应建立一个TCP/IP连接,每次都要重新建立连接。
HTTP1.1中,使用keep-alive进行长连接,多个连续的请求响应可以使用同一个连接。
HTTP1.1keep-alive长连接中,每个请求还是要排队进行,串行化单线程处理,如果某个请求超时,后面就会发生阻塞,都需要继续排队等待。

HTTP2.0

  1. 多路复用:在HTTP1.1的基础上,进行多路复用
  2. 请求优先级:防止关键的请求被阻塞,给每个request设置优先级,优先级高的优先得到响应。比如浏览器加载首页,首先要显示HTML页面,然后才是各种静态资源文件和脚本文件。
  3. 首部压缩:消息头header有很多内容会重复发送的,采用压缩可以减小包的大小和数量。
  4. 服务端推送:服务端会根据请求的资源对需要的资源进行预估,提前发送。比如客户端请求style.css,服务端会将style.js也进行发送,这样当客户端想要获取style.js时就可以直接从缓存读取。
  5. 二进制格式:HTTP1.x的解析是基于文本,HTTP2.0决定协议解析基于二级制格式,健壮性更好。


多路复用


服务端推送

浏览器接受响应报文后

服务器收到比特流后转换为帧格式;发现目的MAC地址与本网卡相同,接着会拆除数据链路层的封装变成数据包,上传到网络层;发现目的IP地址与本机相同,接着会拆除网络层封装变为数据段,上传到传输层,传输层进行排序、重组等,传输到应用层。HTTP服务器,如nginx通过反向代理,将其定位到服务器对应端口位置,该端口处可能有一个NodeJS服务,生成响应报文,比如报文内容为google首页的HTML页面。

反向代理服务器:
用户发出请求都指向调度服务器(为反向代理服务器,比如安装了nginx控制负载均衡),反向代理服务器根据调度算法将请求分配给集群中的服务器执行,调度器等待实际服务器的响应结果,反馈给用户。

后端处理时是会有统一的验证的,如安全拦截、跨域验证等,如果不符合要求会直接返回相应的报文,通过后才会进入实际的执行,执行后返回相应包,多层封装,达成前后端交互。

HTTP响应

https://zhuanlan.zhihu.com/p/34453198

服务器端从固定的端口接收到TCP报文后会解包出HTTP报文,封装成HTTP Request对象供上层使用。

HTTP响应报文主要包括三个部分:状态行、响应头、响应正文。

状态行
1××:指示信息。请求已被接受,继续处理。
2××:成功。请求已成功接收。
3××:重定向。请求需要进一步操作才能完成。
4××:客户端错误。客户端语法错误或请求无法实现。
5××:服务器端错误。服务器未能实现合法请求。

比较常见的状态码有:200, 204, 301, 302, 304, 400, 401, 403, 404, 422, 500。
301和302区别。
HTTP缓存问题。

200:请求成功,请求的资源发送回客户端。
304:请求的资源自上次请求未修改,请使用本地缓存。
400:客户端请求错误(如安全模块拦截)
401:请求未授权
403:禁止访问(如未登录)
404:请求的资源未找到
500:服务器内部错误
503:服务不可用

响应头
常见的有:

Access-Control-Allow-Headers: 服务器端允许的请求Headers
Access-Control-Allow-Methods: 服务器端允许的请求方法
Access-Control-Allow-Origin: 服务器端允许的请求Origin头部(譬如为*)
Content-Type:服务端返回的实体内容的类型
Date:数据从服务器发送的时间
Cache-Control:告诉浏览器或其他客户,什么环境可以安全的缓存文档
Expires:应该在什么时候认为文档已经过期,从而不再缓存它
Max-age:客户端的本地资源应该缓存多少秒,开启了Cache-Control后有效
Last-Modified:请求资源的最后修改时间
ETag:请求变量的实体标签的当前值
Set-Cookie:设置和页面关联的cookie,服务器通过这个头部把cookie传给客户端
Keep-Alive:如果客户端有keep-alive,服务端也会有响应(如timeout=38)
Server:服务器的一些相关信息

请求头和响应头中的内容时进行匹配分析的:

  • 请求头部的Accept要和响应头部的Content-Type匹配,否则会报错
  • 跨域请求时,请求头部的Origin要匹配响应头部的Access-Control-Allow-Origin,否则会报跨域错误
  • 在使用缓存时,请求头部的If-Modified-Since和响应头部的Last-Modified对应
  • 在使用缓存时,请求头部的If-None-Match和响应头部的ETag对应

cookie-session:

客户端的cookie与服务端的session结合使用。

  1. 用户登录后,服务端生成一个session,里面存放用户的信息(用户名、密码等);同时,生成一个sessionid,相当于session的key;
  2. 服务端将sessionid放入setcookie头部,浏览器收到后cookie内就会存储由sessionid;
  3. 浏览器每次发出同域名下的请求时,就会携带cookie,自动校验,有效期内不需要重新登陆。

注意事项:
cookie中避免出现敏感信息,很不安全。如果一定要存储敏感信息,需要进行加密(但还是不安全),或者设置httponly。

存在的问题:
当浏览器访问同域名下的静态资源时(不需要使用cookie),每次请求仍然会携带cookie,造成资源浪费。
优化:
进行多域名拆分,对于静态资源划分到另一个域名下,由于不同域名,请求时不会携带cookie

gzip:
一种压缩格式,压缩率高达70%,压缩效果很好。除了gzip,还有其他压缩格式如deflate,但没有gzip高效。
服务器开启gzip压缩,但需要浏览器支持才有效。

长连接和短连接:

长连接即没建立一次TCP连接可连续发送多个数据包,当没有数据发送时需要发送检测包维持连接。
短连接即每次数据交互都要重新建立连接,发送完成断开连接。

在HTTP1.0中默认使用短连接,每次HTTP操作都要重新建立连接,任务完成后断开连接。比如静态资源请求时就是单独的连接。
HTTP1.1中默认使用长连接,打开一个网页后TCP连接不会中断,当再次访问该服务器时直接使用已有的连接。
表现在请求头中的:Connection:keep-alive
服务器中会配置keep-alive的保持时间。

响应正文
包含了服务器返回给客户端的文本信息,HTML、CSS、JS、图片等文件就包含在这里。

如果响应码为301或302重定向,浏览器会向响应体中的location再次发送请求。

浏览器解析渲染过程

来自: https://www.jianshu.com/p/a5f26487f097

https://segmentfault.com/a/1190000010298038
https://www.cnblogs.com/xiaohuochai/p/9193083.html#anchor1

浏览器的解析过程就是将字节流形式的网页内容构建成DOM树、Render树以及RenderLayer树的过程。

一、浏览器接收到响应报文后,首先用loader模块加载资源。
loader模块加载资源主要有两条路径:主资源加载路径和派生资源加载路径。主资源即index.html文件,派生资源即index.html中用到的资源。
二、主资源到达后,浏览器的parser模块会对资源进行解析,生成派生资源对应的DOM结构,根据需求触发对应的派生资源的加载。
比如:加载过程中遇到img标签,则生成img元素(HTMLImageElement)添加到DOM树上,将其对应的属性进行设置,当设置到src属性时,触发派生资源进行加载。
三、parser模块加载HTML、CSS和JS资源,生成DOM树

  1. 解析HTML,生成DOM树

    这个过程主要有四个步骤:
    解码:将编码过的字节流转换成Unicode字符
    分词:按照一定的切词规则将字符组成词语(Tokens)
    解析:根据语义构建相应的节点(Node)
    建树:将节点关联在一起生成DOM树。

  2. 解析CSS,生成CSSOM规则树

    CSS的解析也类似。CSS样式表中包含一系列CSSRule,每个CSSrule都由选择器(CSSStyleSelector)和声明(CSSStyleDeclaration)组成,CSS声明由属性和值组成。
    CSS解析后会进行CSSRule的匹配,根据选择器找到相应的HTML元素,然后将相应的声明应用上去。
    实际匹配时还会考虑到继承、优先级等问题。

  3. 解析JS
    JavaScript一般由JavaScript引擎线程进行解析,它能够动态的改变DOM树,为DOM节点添加事件响应处理函数,根据事件、时间映射一颗DOM树到另一颗DOM树。

经过parser模块解析,已经形成了节点带有style、能够响应自定义事件的DOM树。

解析HTML时遇到静态资源外链的下载:
会开启一个下载线程去下载资源。(对于HTTP1.1,每个资源的下载都要新开一个TCP/IP连接)
CSS样式资源:

  • 异步下载
  • 不会阻塞DOM树构建。
  • 会阻塞render树构建(阻塞渲染)。
  • 由media query声明时不会阻塞render树构建。
    JS脚本资源:
  • 普通的脚本会阻塞浏览器解析HTML
  • 带有defer和async属性时脚本异步,可以先解析再执行
  • 不阻塞下载,可以并行下载其他资源,但不可解析
defer和async:

defer时延迟执行,async时异步执行。
async指异步下载完后再执行,此时一定在onload前,但对于DOMContentLoaded是不确定的
defer指延迟到看起来脚本是在body后面一样,按规范应该是在DOMContentLoaded之前,但不同浏览器实际可能不同。

loaded和DOMContentLoaded:

DOMContengLoaded:DOM加载完成,不包括样式表、图片等(如果有async脚本不一定完成)

loaded:DOM、样式表、图片都加载完成。

img图片资源:异步下载,不阻塞解析,下载完后会将图片替换src的地方。

渲染阻塞

当遇到一个script标签时,DOM 构建会被暂停,直至脚本完成执行,然后继续构建 DOM 树。

但如果 JS 依赖 CSS 样式,而它还没有被下载和构建时,浏览器就会延迟脚本执行,直至 CSS Rules 被构建。

所有我们知道:

CSS 会阻塞 JS 执行

JS 会阻塞后面的 DOM 解析

为了避免这种情况,应该以下原则:

CSS 资源排在 JavaScript 资源前面

JS 放在 HTML 最底部,也就是 前

另外,如果要改变阻塞模式,可以使用 defer 与 async

  1. 合并两者,生成render tree
    最终的render树和DOM树相似,但对于不可见的DOM元素不会渲染到DOM树上,比如head这种不可见标签,以及display为none的标签

  2. 布局render树(layout/reflow),计算各节点大小、位置
    通过渲染树中的信息,计算每个渲染对象的尺寸和位置

  3. 绘制render树(paint),绘制页面像素信息
    调用呈现器的paint方法将呈现器上的内容显示在屏幕上。

重排和重绘:
重排:元素的尺寸、位置、形状、结构、内容发生变化时,需要重新计算样式和渲染树。
重绘:元素的背景色、边框色、文字颜色发生变化时需要用新样式绘制元素。

重排一定重绘,重绘不一定重排。

引起重排的情况:

  1. 页面初始渲染
  2. 尺寸、结构变化(字体大小、边框宽度)
  3. DOM结构改变,比如添加或删除节点(appendChild)
  4. render树结构改变,比如改变padding
  5. 窗口resize
  6. 计算某些属性:
    (1)offset(top/right/width/height)
    (2)scroll(top/right/width/height)
    (3)client(top/right/width/height)
    (4)width/height
    (5)getComputedStyle()或IE的currentStyle
var s = document.body.style;s.padding = "2px"; // 回流+重绘
s.border = "1px solid red"; // 再一次 回流+重绘
s.color = "blue"; // 再一次重绘
s.backgroundColor = "#ccc"; // 再一次 重绘
s.fontSize = "14px"; // 再一次 回流+重绘
// 添加node,再一次 回流+重绘
document.body.appendChild(document.createTextNode('abc!'));

减少重排重绘:
修改样式时定义为class一次性更新
避免多次计算offset属性,需要多次使用时存在变量里
复杂的元素用绝对定位或者固定定位,脱离文档流
避免频繁操作DOM,最好创建一个div,在里面应用所有的DOM操作,最后在添加到window.document。

Web优化

  • 能不从网络中加载的资源就不从网络中加载,合理使用缓存,把资源放在浏览器
  • 必须从网络中加载时尽量减少连接时间,DNS优化(缓存、预解析等),长连接,HTTP2多路复用
  • 减少响应内容的大小,对内容进行压缩,
  • 减少需要加载的资源数目
  • 获得资源后进行解析渲染,尽量减少重排和重绘。

【WEB】从输入URL到页面渲染完成相关推荐

  1. url上接收到 el表达式 不渲染_一文摸透从输入URL到页面渲染的过程

    一文摸透从输入URL到页面渲染的过程 从输入URL到页面渲染需要Chrome浏览器的多个进程配合,所以我们先来谈谈现阶段Chrome浏览器的多进程架构. 一.Chrome架构 目前Chrome采用的是 ...

  2. 浏览器从输入URL到页面渲染过程 ——页面渲染流程

    之前我有总结过一篇经典面试题:浏览器从输入URL到页面渲染过程 ,接下里我将对某些知识点进行更细致的解析. 浏览器从输入URL到页面渲染过程 系列文章: (一):浏览器从输入URL到页面渲染过程 -- ...

  3. 一文通透从输入URL到页面渲染的全过程----高频面试

    一文通透从输入URL到页面渲染的全过程----高频面试 喜欢大海 喜欢夕阳 写下便是永恒 文章目录 一文通透从输入URL到页面渲染的全过程----高频面试 重温 进程与线程 什么是进程 什么是线程 进 ...

  4. 浏览器从输入URL到页面渲染过程 —— 浏览器的进程与线程

    之前我有总结过一篇经典面试题:浏览器从输入URL到页面渲染过程,接下里我将对某些知识点进行更细致的解析. 浏览器从输入URL到页面渲染过程 系列文章: (二):浏览器从输入URL到页面渲染过程 --页 ...

  5. 浏览器 重定向次数限制_在浏览器输入URL到页面渲染的整个流程是如何的?都有哪些步骤?...

    问题:输入 URL 到页面渲染的整个流程 DNS解析 TCP握手 TLS握手 浏览器开始解析文件 构建 DOM 树.构建 CSSOM 树.解析JS 生成 Render 树 调用 GPU 绘制,合成图层 ...

  6. 从输入URL到页面渲染完成 -戈多编程

    1.输入URL地址 2.浏览器根据域名查询IP地址 3.浏览器发送HTTP请求到web服务器 4.服务器返回一个永久重定向响应 5.浏览器会跟踪重定向地址 6.服务器处理请求 7.服务器返回一个HTM ...

  7. 从输入url到页面渲染完成经历的那些事~

    网络部分 1. DNS域名解析 第一个过程:将域名解析为对应的IP地址. 查找流程:浏览器缓存 -> 系统缓存 -> 系统hosts文件 -> 路由器缓存 -> 本地DNS服务 ...

  8. 输入 URL 到页面渲染的整个流程

    1.DNS解析,通过域名查询到具体的 IP 2.TCP三次握手(客户端向服务端发送连接请求报文段.服务端收到连接请求报文段后,如果同意连接,则会发送一个应答.当客户端收到连接同意的应答后,还要向服务端 ...

  9. 从在浏览器中输入URL到页面渲染出来的完整过程是怎样的?

    从宏观上看,主要包括以下几个步骤:域名解析.建立连接.发送请求.响应数据.关闭连接.下面以在Chrome浏览器中输入https://yq.aliyun.com/articles/580962为例,讨论 ...

最新文章

  1. Blender钢铁机器人建模与动画全流程制作视频教程
  2. 安装nginx0.7x+php5.2.8(Fastcgi)小结
  3. mysql主从(GTID复制模式)
  4. 现代密码学1.3--古典密码/historical cipher
  5. 并发编程知识点一张图总结
  6. camunda流程定义表无数据_BPM - 业务流程管理
  7. Android -- 自定义ProgressBar图片
  8. 体验一下Oracle 11g物理Active Data Guard实时查询(Real-time query)
  9. 7-1 寻找大富翁 (25 分)(思路加详解+两种做法(一种优先队列,一种vector容器))
  10. 少儿编程100讲轻松学python(六)-pycharm怎么汉化?
  11. Jmeter插件-dubbo
  12. OpenStack 是什么
  13. 做网站买主机还是服务器,做网站是买服务器还是买主机
  14. LIRe提供的6种图像特征描述方法的评测
  15. STL源码剖析学习十四:算法之set相关算法
  16. 34个省级行政区简图_全国23个省中,为什么广东要分为21个地级市?今天总算知道了...
  17. HarmonyOS 组件篇
  18. EF批量添加数据BulkInsert
  19. bin文件如何编辑_如何加密PDF?使用福昕PDF编辑器加密PDF文件实操
  20. MySQL数据库学习日志(一):数据库概述及SQL语言基础

热门文章

  1. 对野生动物的GPS信息,进行数据库查询
  2. 携创教育:函授本科全国承认吗?成人高考学历含金量是不是很低?
  3. 【NodeJs】使用ffmpeg将视频webm转换为mp4
  4. Arduino SimpleFOC库-007-电流感应
  5. 区块链项目包装方法有哪些?深入分析一站式包装技巧和手段
  6. 基于java幸福婚庆策划网管理系统
  7. 给任意边长n,打印出一个一n为边长的空心*型菱形(C语言实现)
  8. 咏月华暮思别沉——寄予我的大学生活
  9. 2022年期末网页设计作业——如何制作企业网站(html+css制作)
  10. 北师大 外国教育史-3(文艺复兴时期的教育、宗教改革时期的教育)