将USB设备使用情况看个清楚
在电脑中插入了USB设备并被移除之后,会在系统中留下什么痕迹吗?如果我们需要了解USB设备在本系统中曾经或正在使用的情况,可以用USBDeview这款小软件来查明。
文|如云
利用USBDeview(下载地址:http://www.nirsoft.net/utils/usbdeview.zip或http://www.nirsoft.net/utils/usbdeview-x64.zip,为32位和64位两种程序),我们可以列出当前连接到电脑或曾连接过该电脑的所有USB设备。该软件不用安装,下载并解包后直接运行EXE程序即可启动。
启动软件后,窗口中会列出所有在该系统插入或插入过并被记录下来的USB设备的信息,记录的项目达40种之多。其中主要项目有:“Device Name”为设备名称、“Description”为设备描述、“Device Type”为设备类型、“Connected”为是否已连接、“Safe To Unplug”为是否支持安全拔插、“Serial Number”为设备序列号、“Registry Time 1”为设备最近添加时间、“Registry Time 2”为设备上次连接时间、“Firmware Revision”为设备固件版本、“Hub/Port”为连接的Hub和端口编号、“Driver Filename”为设备驱动程序名称、“Driver InfPath”为设备驱动信息文件路径。从这些信息中,我们便可以看出是什么样的设备在什么时间连接了哪个端口,设备型号、驱动程序以及其他具体属性如何等情况。
如果需要断开某个设备的连接,只需在选中该设备条目后点击工具栏中的红宝石按钮,这时“Disabled”一栏将显示“Yes”;重新连接点击绿宝石按钮;点击蓝宝石按钮则是断开后再立即自动连接,相当于刷新一下设备的连接。
当需要卸载列表中的某个设备时,选中该设备并点击工具栏中的垃圾桶图标即可;或者也可以通过右键菜单选择“Uninstall Selected Devices”。
设备的右键菜单是一个比较万能的操作渠道,在其中我们不仅可以完成上述的设备断开、连接、重新连接等动作,还可以创建设备的桌面快捷方式、打开相关设备、自动播放、打开注册表相关选项、打开设备INF文件、查看设备属性等。我们还可以通过右键菜单命令测试连接某些设备的读/写速度。
如果需要将选定的设备列表导出为文本/HTML或XML格式,可以选择“HTML Report - Selected Iterms”菜单命令操作,“HTML Report - All Iterms”为导出所有选项;或者直接点击工具栏中的磁盘按钮。导出的格式还可以是TXT、CSV等。
该程序还支持通过命令行来操作。具体参数的使用以及命令案例,请参阅主程序目录中的USBDeview.chm帮助文件。
此外,“Options”菜单中有许多有用的选项,如隐藏启动、置顶、退缩到任务栏等。CF
叠样式表(Cascading Style Sheet,简称:CSS)是为网页添加样式的代码。本节将介绍 CSS 的基础知识,并解答类似问题:怎样将文本设置为黑色或红色?怎样将内容显示在屏幕的特定位置?怎样用背景图片或颜色来装饰网页?
CSS 究竟什么来头?
和 HTML 类似,CSS 也不是真正的编程语言,甚至不是标记语言。它是一门样式表语言,这也就是说人们可以用它来选择性地为 HTML 元素添加样式。举例来说,要选择一个 HTML 页面里所有的段落元素,然后将其中的文本改成红色,可以这样写 CSS:
p {
color: red;
}
不妨试一下:首先新建一个 styles 文件夹,在其中新建一个 style.css 文件,将这三行 CSS 保存在这个新文件中。
然后再将该 CSS 文件连接至 HTML 文档,否则 CSS 代码不会对 HTML 文档在浏览器里的显示效果有任何影响。(如果你没有完成前几节的实践,请复习处理文件 和 HTML 基础。在笔记本里有这个方面的内容!)
1、打开 index.html 文件,然后将下面一行粘贴到文档头(也就是 <head> 和 </head> 标签之间)。
<link href="styles/style.css" rel="stylesheet">
2、保存 index.html 并用浏览器将其打开。应该看到以下页面:
如果段落文字变红,那么祝贺你,你已经成功地迈出了 CSS 学习的第一步。
“CSS 规则集”详解
让我们来仔细看一看上述CSS:
整个结构称为 规则集(通常简称“规则”),各部分释义如下:
- 选择器(Selector)
- HTML 元素的名称位于规则集开始。它选择了一个或者多个需要添加样式的元素(在这个例子中就是 p 元素)。要给不同元素添加样式只需要更改选择器就行了。
- 声明(Declaration)
- 一个单独的规则,比如说 color: red; 用来指定添加样式元素的属性。
- 属性(Properties)
- 改变 HTML 元素样式的途径。(本例中 color 就是 `` 元素的属性。)CSS 中,由编写人员决定修改哪个属性以改变规则。
- 属性的值(Property value)
- 在属性的右边,冒号后面即属性的值,它从指定属性的众多外观中选择一个值(我们除了 red 之外还有很多属性值可以用于 color )。
注意其他重要的语法:
- 每个规则集(除了选择器的部分)都应该包含在成对的大括号里({})。
- 在每个声明里要用冒号(:)将属性与属性值分隔开。
- 在每个规则集里要用分号(;)将各个声明分隔开。
如果要同时修改多个属性,只需要将它们用分号隔开,就像这样:
p {
color: red;
width: 500px;
border: 1px solid black;
}
多元素选择
也可以选择多种类型的元素并为它们添加一组相同的样式。将不同的选择器用逗号分开。例如:
p, li, h1 {
color: red;
}
不同类型的选择器
选择器有许多不同的类型。上面只介绍了元素选择器,用来选择 HTML 文档中给定的元素。但是选择的操作可以更加具体。下面是一些常用的选择器类型:
选择器名称 | 选择的内容 | 示例 |
元素选择器(也称作标签或类型选择器) | 所有指定(该)类型的 HTML 元素 | p 选择 <p> |
ID 选择器 | 具有特定 ID 的元素(单一 HTML 页面中,每个 ID 只对应一个元素,一个元素只对应一个 ID) | #my-id 选择 <p id="my-id"> 或 <a id="my-id"> |
类选择器 | 具有特定类的元素(单一页面中,一个类可以有多个实例) | .my-class 选择 <p class="my-class"> 和 <a class="my-class"> |
属性选择器 | 拥有特定属性的元素 | img[src] 选择 <img src="myimage.png"> 而不是 <img> |
伪(Pseudo)类选择器 | 特定状态下的特定元素(比如鼠标指针悬停) | a:hover 仅在鼠标指针悬停在链接上时选择 <a>。 |
选择器的种类远不止于此,更多信息请参阅 选择器。
字体和文本
译注:再一次说明,中文字体文件较大,不适合直接用于 Web Font。
在探索了一些 CSS 基础后,我们来把更多规则和信息添加至 style.css 中,从而让示例更美观。首先,让字体和文本变得更漂亮。
第一步:找到之前Google Font 输出的地址。并以<link>元素的形式添加进index.html文档头(<head>和</head>之间的任意位置)。代码如下:
<link href="https://fonts.font.im/css?family=Open+Sans" rel="stylesheet" type="text/css">
以上代码为当前网页下载 Open Sans 字体,从而使自定义 CSS 中可以对 HTML 元素应用这个字体。
第二步:接下来,删除 style.css 文件中已有的规则。虽然测试是成功的了,但是红字看起来并不太舒服。
第三步:将下列代码添加到相应的位置,用你在 Google Fonts 找到的字体替代 font-family 中的占位行。( font-family 意味着你想要你的文本使用的字体。)这条规则首先为整个页面设定了一个全局字体和字号(因为 <html> 是整个页面的父元素,而且它所有的子元素都会继承相同的 font-size 和 font-family):
html {
/* px 表示 “像素(pixels)”: 基础字号为 10 像素 */
font-size: 10px;
/* Google fonts 输出的 CSS */
font-family: 'Open Sans', sans-serif;
}
注:CSS 文档中所有位于 /* 和 */ 之间的内容都是 CSS 注释,它会被浏览器在渲染代码时忽略。你可以在这里写下对你现在要做的事情有帮助的笔记。
译注:/*``*/ 不可嵌套,/*这样的注释是/*不行*/的*/。CSS 不接受 // 注释。
接下来为文档体内的元素(<h1> (en-US)、<li>和<p>)设置字号。将标题居中显示,并为正文设置行高和字间距,从而提高页面的可读性。
h1 {
font-size: 60px;
text-align: center;
}
p, li {
font-size: 16px;
/* line-height 后而可以跟不同的参数,如果是数字,就是当前字体大小乘上数字 */
line-height: 2;
letter-spacing: 1px;
}
可以随时调整这些 px 值来获得满意的结果,以下是大体效果:
一切皆盒子
编写 CSS 时你会发现,你的工作好像是围绕着一个一个盒子展开的——设置尺寸、颜色、位置,等等。页面里大部分 HTML 元素都可以被看作若干层叠的盒子。
并不意外,CSS 布局主要就是基于盒模型的。每个占据页面空间的块都有这样的属性:
- padding:即内边距,围绕着内容(比如段落)的空间。
- border:即边框,紧接着内边距的线。
- margin:即外边距,围绕元素外部的空间。
这里还使用了:
- width :元素的宽度
- background-color :元素内容和内边距底下的颜色
- color :元素内容(通常是文本)的颜色
- text-shadow :为元素内的文本设置阴影
- display :设置元素的显示模式(暂略)
开始在页面中添加更多 CSS 吧!大胆将这些新规则都添加到页面的底部,而不要纠结改变属性值会带来什么结果。
更改页面颜色
html{
background-color:#00539f;
}
这条规则将整个页面的背景颜色设置为 所计划的颜色。
文档体格式设置
body{
width:600px;
margin:0 auto;
background-color:#ff9500;
padding:0 20px 20px 20px;
border:5px solid black;
}
现在是 <body> 元素。以上条声明,我们来逐条查看:
- width: 600px; —— 强制页面永远保持 600 像素宽。
- margin: 0 auto; —— 为 margin 或 padding 等属性设置两个值时,第一个值代表元素的上方和下方(在这个例子中设置为 0),而第二个值代表左边和右边(在这里,auto 是一个特殊的值,意思是水平方向上左右对称)。你也可以使用一个,三个或四个值,参考 这里 。
- background-color: #FF9500; —— 如前文所述,指定元素的背景颜色。我们给 body 用了一种略微偏红的橘色以与深蓝色的 `` 元素形成反差,你也可以尝试其它颜色。
- padding: 0 20px 20px 20px; —— 我们给内边距设置了四个值来让内容四周产生一点空间。这一次我们不设置上方的内边距,设置右边,下方,左边的内边距为20像素。值以上、右、下、左的顺序排列。
- border: 5px solid black; —— 直接为 body 设置 5 像素的黑色实线边框。
定位页面主标题并添加样式
h1{
margin: 0;
padding:20px 0;
color: #00539f;
text-shadow:3px 3px 1px black
}
你可能发现页面的顶部有一个难看的间隙,那是因为浏览器会在没有任何 CSS 的情况下 给 <h1>en-US等元素设置一些默认样式。但这并不是个好主意,因为我们希望一个没有任何样式的网页也有基本的可读性。为了去掉那个间隙,我们通过设置margin: 0;来覆盖默认样式。
至此,我们已经把标题的上下内边距设置为 20 像素,并且将标题文本与 HTML 的背景颜色设为一致。
需要注意的是,这里使用了一个 text-shadow 属性,它可以为元素中的文本提供阴影。四个值含义如下:
- 第一个值设置水平偏移值 —— 即阴影右移的像素数(负值左移)。
- 第二个值设置垂直偏移值 —— 即阴影下移的像素数(负值上移)。
- 第三个值设置阴影的模糊半径 —— 值越大产生的阴影越模糊。
- 第四个值设置阴影的基色。
不妨尝试不同的值看看能得出什么结果。
图像居中
img{
display:block;
margin:0 auto;
}
最后,我们把图像居中来使页面更美观。可以复用 body 的margin: 0 auto,但是需要一点点调整。<body>元素是块级元素,意味着它占据了页面的空间并且能够赋予外边距和其他改变间距的值。而图片是内联元素,不具备块级元素的一些功能。所以为了使图像有外边距,我们必须使用display: block 给予其块级行为。
注:以上说明假定所选图片小于页面宽度(600 pixels)。更大的图片会溢出 body 并占据页面的其他位置。要解决这个问题,可以:
1)使用 图片编辑器 来减小图片宽度; 2)用 CSS 限制图片大小,即减小 <img> 元素 width 属性的值(比如 400 px)。
注:如果你暂时不能理解 display: block 和块级元素与行内元素的差别也没关系;随着你对 CSS 学习的深入,你将明白这个问题。
小结
如果你按部就班完成本文的实践,那么最终可以得到以下页面
相关推荐:
前端新手看过来,手把手带你轻松上手html的实操
我们向浏览器的地址栏输入URL的时候,网络会进行一系列的操作,最终获取到我们所需要的文件,如何交给浏览器进行渲染
我们所关注的问题也就是:
大致的执行顺序
- URL解析
- DNS 解析:缓存判断 + 查询IP地址
- TCP 连接:TCP 三次握手
- SSL/TLS四次握手(只有https才有这一步)
- 浏览器发送请求
- 服务器响应请求并返回数据
- 浏览器解析渲染页面
- 断开连接:TCP 四次挥手
URL解析
浏览器先会判断输入的字符是不是一个合法的URL结构,如果不是,浏览器会使用搜索引擎对这个字符串进行搜索
URL结构组成
https://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#anchor
- 协议:https:// 互联网支持多种协议,必须指明网址使用哪一种协议,默认是 HTTP 协议。 也就是说,如果省略协议,直接在浏览器地址栏输入www.example.com,那么浏览器默认会访问http://www.example.com。 HTTPS 是 HTTP 的加密版本,出于安全考虑,越来越多的网站使用这个协议。
- 主机:www.example.com 主机(host)是资源所在的网站名或服务器的名字,又称为域名。上例的主机是www.example.com。 有些主机没有域名,只有 IP 地址,比如192.168.2.15。
- 端口:https:// 同一个域名下面可能同时包含多个网站,它们之间通过端口(port)区分。 “端口”就是一个整数,可以简单理解成,访问者告诉服务器,想要访问哪一个网站。 默认端口是80,如果省略了这个参数,服务器就会返回80端口的网站。 端口紧跟在域名后面,两者之间使用冒号分隔,比如www.example.com:80。
- 路径:/path/to/myfile.html 路径(path)是资源在网站的位置。比如,/path/index.html这个路径,指向网站的/path子目录下面的网页文件index.html 互联网的早期,路径是真实存在的物理位置。现在由于服务器可以模拟这些位置,所以路径只是虚拟位置 路径可能只包含目录,不包含文件名,比如/foo/,甚至结尾的斜杠都可以省略 这时,服务器通常会默认跳转到该目录里面的index.html文件(即等同于请求/foo/index.html),但也可能有其他的处理(比如列出目录里面的所有文件),这取决于服务器的设置 一般来说,访问www.example.com这个网址,很可能返回的是网页文件www.example.com/index.html
- 查询参数:?key1=value1&key2=value2 查询参数(parameter)是提供给服务器的额外信息。参数的位置是在路径后面,两者之间使用?分隔 查询参数可以有一组或多组。每组参数都是键值对(key-value pair)的形式,同时具有键名(key)和键值(value),它们之间使用等号(=)连接。比如,key1=value就是一个键值对,key1是键名,value1是键值 多组参数之间使用&连接,比如key1=value1&key2=value2
- 锚点:#anchor 锚点(anchor)是网页内部的定位点,使用#加上锚点名称,放在网址的最后,比如#anchor 浏览器加载页面以后,会自动滚动到锚点所在的位置 锚点名称通过网页元素的id属性命名
DNS解析
DNS(Domain Names System),域名系统,是互联网一项服务,是进行域名和与之相对应的 IP 地址进行转换的服务器
第一步:缓存判断
判断是正确的URL格式之后,DNS会在我们的缓存中查询是否有当前域名的IP地址
基本步骤:
- 浏览器缓存:浏览器检查是否在缓存中
- 操作系统缓存:操作系统DNS缓存,去本地的hosts文件查找
- 路由器缓存:路由器DNS缓存
- ISP 缓存: ISP DNS缓存(ISP DNS 就是在客户端电脑上设置的首选 DNS 服务器,又称本地的DNS服务器)
在经历上述缓存查找还没有找到的话,就进行下一步查询操作
第二步:查询IP地址
浏览器会去根域名服务器中查找,如果还没有就去顶级域名服务器中查找,最后是权威域名服务器。
找到IP地址后,将它记录在缓存中,供下次使用。
TCP连接:三次握手
简单理解
简单的理解就是:
客户端:hello,你好,你是server吗?
服务端:hello,你好,我是server,你是client吗
客户端:yes,我是client
开始数据传输.....
——————————————————————————————————————————
客户端(男人):我喜欢你,咱俩处对象吧
服务端(女人):我也喜欢你,我答应你
客户端(男人):太棒了,我们现在去看电影吧
开始数据传输.....
然后双方就正确建立连接,开始传输数据
详细分析
- 第一次握手:客户端发送一个带 SYN=1,Seq=x 的数据包到服务器端口 第一次握手,由浏览器发起,告诉服务器我要发送请求了 SYN(synchronous):请求建立连接 seq(sequence):随机序列号 请注意TCP规定SYN被设置为1的报文段不能携带数据但要消耗掉一个序号。
- 第二次握手:服务器发回一个带 SYN=1, ACK=1, seq=y, ack=x+1 的响应包以示传达确认信息 第二次握手,由服务器发起,告诉客户端我准备接受了,你赶紧发送吧 ACK(acknowledgement):确认,是一个确定字符 ack:ack=上一次的seq+1,作用是接受上一次远端主机传来的seq,加一然后再传给客户端,提示客户端已经成功接收上一次所有数据 请注意这个报文段不能携带数据,因为它是SYN被设置为一的报文段但同样要消耗掉一个序号
- 第三次握手:客户端再回传一个带 ACK,seq=x + 1, ack=y + 1 的数据包,代表“握手结束” 第三次握手,由浏览器发送,告诉服务器,我马上就发了,准备接受吧 确认报文段可以携带数据。但如果不携带数据则不消耗序号,在这种情况下所发送的下一个数据报文段的序号仍是x + 1
然后双方就正确建立连接,开始传输数据
SSL/TLS四次握手
HTTPS 建立连接的过程,先进行 TCP 三次握手,再进行 TLS 四次握手(仅对https)
因为 HTTPS 都是基于 TCP 传输协议实现的,得先建立完可靠的 TCP 连接才能做 TLS 握手的事情。
第一次握手:客户端发出请求Client Hello
- 首先,客户端先向服务器发出加密通信的请求,这被叫做clienthello请求。
- 在这一步,客户端主要向服务器提供以下信息:
- 支持的协议版本,比如TLS1.0版本
- 支持的加密方法,比如RSA公钥加密
- 一个客户端生成的随机数(client random), 稍后用于生成对话密钥(session key)
第二次握手:服务器回应Server Hello
- 服务器收到客户端请求后,向客户端发出回应,这叫做serverhello
- 这一步服务器主要干三件事:
- 确认使用的加密通信协议版本,比如TLS1.00版本。如果游览器与服务器支持的版本不一致,服务器关闭加密通信
- 确认使用的加密方法(客户端所支持),比如RSA公钥加密
- 将服务器证书、非对称加密的公钥,以及一个随机数(Server random)发送给客户端游览器
客户端验证证书
客户端收到服务器回应以后,首先验证服务器证书,验证手段就是执行如下三种检查:
- 检查证书是否已过期;
- 检查证书中的域名与实际域名是否一致
- 检查证书是否是可信机构颁布的
如果,上述过程中有任何一个环节发现问题,那么浏览器就会向访问者显示一个警告,由其选择是否还要继续通信。如果证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串新的随机数(Premaster secret )。
第三次握手:客户端回应
此时,浏览器会根据前三次握手中的三个随机数:
- Client random
- Server random
- Premaster secret
通过一定的算法来生成 “会话密钥” (Session Key),这个会话密钥就是接下来双方进行对称加密解密使用的密钥!
第四次握手:服务端回应
服务端收到客户端的回复,利用已知的加密解密方式进行解密,服务器收到客户端的第三个随机数( Premaster secret) 之后,使用同样的算法计算出 “会话密钥” (Session Key)。
至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用 “会话密钥” 加密内容。(非对称加密解密将不再使用,接下来完全由对称加密接手了,因为密钥已经安全的传送给了通信的双方)
总结
- 客户端请求建立SSL链接,并向服务发送一个随机数–Client random和客户端支持的加密方法,比如RSA公钥加密,此时是明文传输
- 服务端回复一种客户端支持的加密方法、一个随机数–Server random、授信的服务器证书和非对称加密的公钥
- 客户端收到服务端的回复后利用服务端的公钥,加上新的随机数–Premaster secret 通过服务端下发的公钥及加密方法进行加密,发送给服务器
- 服务端收到客户端的回复,利用已知的加解密方式进行解密,同时利用Client random、Server random和Premaster secret通过一定的算法生成HTTP链接数据传输的对称加密key – session key
浏览器发送请求
连接建立成功之后,浏览器向服务器发送HTTP请求报文,来获取自己想要的数据
请求报文由请求行、请求头、空行、请求体四部分组成
- 请求行:有请求方法、请求的url、http协议及其版本
- 请求头:把浏览器的一些基础信息告诉服务器。比如包含了浏览器所使用的操作系统、浏览器内核等信息,以及当前请求的域名信息、浏览器端的 Cookie 信息等
- 空行:最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头
- 请求体(报文主体/请求中文):当使用POST, PUT等方法时,通常需要客户端向服务器传递数据。这些数据就储存在请求正文中。在请求包头中有一些与请求正文相关的信息,例如: 现在的Web应用通常采用Rest架构,请求的数据格式一般为json。这时就需要设置Content-Type: application/json。
服务端响应请求并返回数据
服务器对http请求报文进行解析,并给客户端发送HTTP响应报文对其进行响应
HTTP响应报文也是由状态行、响应头、空行、响应体四部分组成
- 响应行/状态行:由 HTTP 版本协议字段、状态码和状态码的描述文本 3 个部分组成
- 响应头:用于指示客户端如何处理响应体,告诉浏览器响应的类型、字符编码和字节大小等信息
- 空行:最后一个响应头部之后是一个空行,发送回车符和换行符,通知服务器以下不再有响应头部。
- 响应体:返回客户端所需数据
这个时候浏览器拿到我们服务器返回的HTML文件,可以开始解析渲染页面
浏览器解析渲染页面
当我们经历了上述的一系列步骤之后,我们的浏览器就拿到了我的HTML文件那么它又是如何解析整个页面并且最终呈现出我们的网页呢?
渲染流程图
简图:从这张图上我们可以得出一个重要的结论:下载CSS文件并不会阻塞HTML的解析
详图:
详细解析步骤
解析一:HTML解析过程
默认情况下服务器会给浏览器返回index.html文件,所以解析HTML是所有步骤的开始:解析HTML,会 构建DOM Tree
当遇到我们的script文件的时候,我们是不能进行去构建DOM Tree的。它会停止继续构建,首先下载JavaScript代码,并且执行JavaScript的脚本,只有等到JavaScript脚本执行结束后,才会继续解析HTML,构建DOM树。
具体的相关细节看下面的script与页面解析
解析二:生成CSS规则
- 在解析的过程中,如果遇到CSS的link元素,那么会由浏览器负责下载对应的CSS文件
- 浏览器下载完CSS文件后,就会对CSS文件进行解析,解析出对应的规则树
- 我们可以称之为 CSSOM (CSS Object Model,CSS对象模型)
解析三:构建Render Tree
当有了 DOM Tree 和 CSSOM Tree 后,就可以两个结合来 构建 Render Tree
- 注意一:link元素不会阻塞DOM Tree的构建过程,但是会阻塞Render Tree的构建过程
- 因为Render Tree在构建时,需要对应的CSSOM Tree。当我们DOMTree解析完成的时候,如果CSSOM Tree没解析完成就会阻塞。当然一般情况下浏览器会进行优化处理,不会傻傻的等待
- 注意二:Render Tree和DOMTree并不是一一对应的关系
- 比如对于display为none的元素,压根不会出现在render tree中
解析四:布局(layout)和绘制(Paint)
- 第四步是在**渲染树(Render Tree)**上运行 布局(Layout) 以计算每个节点的几何体。 渲染树会 表示 要显示哪些节点以及其他样式,但是 不表示 每个节点的尺寸、位置 等信息 布局的主要目的是为了确定呈现树中所有节点的宽度、高度和位置信息
- 第五步是将每个节点 绘制(Paint) 到屏幕上 在绘制阶段,浏览器将布局阶段计算的 每个frame转为屏幕上实际的像素点 包括 将元素的可见部分进行绘制,比如文本、颜色、边框、阴影、替换元素(比如img)
特殊解析:composite合成
- 绘制的过程,可以将布局后的元素绘制到多个合成图层中【这是浏览器的一种优化手段】
- 默认情况下,标准流中的内容都是被绘制在同一个图层(Layer)中的
- 而一些特殊的属性,会创建一个新的合成层(Compositinglayer ),并且新的图层可以利用GPU来加速绘制
- 那么哪些属性可以形成新的合成层呢?常见的一些属性:
- 3D transforms
- video、canvas、iframe
- opacity动画转换时
- position: fixed
- will-change:一个实验性的属性,提前告诉浏览器元素可能发生哪些变化
- animation或 transition设置了opacity、transform
- 分层确实可以提高性能,但是它以内存管理为代价,因此不应作为web性能优化策略的一部分过度使用
其他相关概念
回流
- 回流reflow(也可以称之为重排) 第一次确定节点的大小和位置,称之为布局(layout) 之后对节点的大小、位置修改 重新计算 称之为回流
- 什么情况下引起回流呢? 比如DOM结构发生改变(添加新的节点或者移除节点) 比如改变了布局(修改了width、height、padding、font-size等值) 比如窗口resize(修改了窗口的尺寸等) 比如调用getComputedStyle方法获取尺寸、位置信息
重绘
- 重绘repaint【字面理解就是对页面再做绘制】 第一次渲染内容称之为绘制(paint) 之后重新渲染称之为重绘
- 什么情况下会引起重绘呢? 比如修改背景色、文字颜色、边框颜色、样式等
联系
- 回流一定会引起重绘,所以回流是一件很消耗性能的事情。
- 所以在开发中要尽量避免发生回流 修改样式时尽量一次性修改【比如通过cssText修改,比如通过添加class修改】 尽量 避免频繁的操作DOM【我们可以在一个DocumentFragment或者父元素中将要操作的DOM操作完成,再一次性的操作】 尽量 避免通过getComputedStyle获取尺寸、位置等信息 对某些元素使用position的absolute或者fixed【并不是不会引起回流,而是开销相对较小,不会对其他元素造成影响】
script元素
script元素和页面联系
- 我们现在已经知道了页面的渲染过程,但是JavaScript在哪里呢? 事实上,浏览器在解析HTML的过程中,遇到了 script元素是不能继续构建DOM树的 它会 停止继续构建,首先下载JavaScript代码,并且执行JavaScript的脚本 只有 等到JavaScript脚本执行结束后,才会继续解析HTML,构建DOM树
- 为什么要这样做呢? 这是 因为JavaScript的作用之一就是操作DOM,并且可以修改DOM 如果我们等到DOM树构建完成并且渲染再执行JavaScript会造成严重的回流和重绘,影响页面的性能 所以会在遇到script元素时,优先下载和执行JavaScript代码,再继续构建DOM树
- 但是这个也往往会带来新的问题,特别是现代页面开发中: 在目前的开发模式中(比如Vue、React),脚本往往比HTML页面更“重”,处理时间需要更长 所以会造成页面的解析阻塞,在脚本下载、执行完成之前,用户在界面上什么都看不到
- 为了解决这个问题,script元素给我们提供了两个属性(attribute) : defer和async
defer属性
- defer属性告诉浏览器 不要等待脚本下载,而继续解析HTML,构建DOM Tree
- 脚本会 由浏览器来进行下载,但是不会阻塞DOM Tree的构建过程
- 如果脚本提前下载好了,它会 等待DOM Tree构建完成,在DOMContentLoaded事件之前先执行defer中的代码
- 所以DOMContentLoaded总是会等待defer中的代码先执行完成
<script src="./foo.js" defer></script>
<script>
window.addEventListener("DOMContentLoaded",()=>{
console.log("DOMContentLoaded");
})
</script>
- 多个带defer的脚步是可以保持正确的执行顺序的
- 从某种角度来说,defer可以提高页面的性能,并且推荐放到head元素中
- 注意:defer仅适用于外部脚本,对于script默认内容会被忽略
async属性
- async特性与defer有些类似,它也能够让脚本不阻塞页面
- async是让一个脚本完全独立的:
- 浏览器 不会因async 脚本而阻塞(与defer类似)
- async脚本不能保证顺序,它是独立下载、独立运行,不会等待其他脚本
- async不会能保证在DOMContentLoaded之前或者之后执行
- defer通常用于需要在文档解析后操作DOM的JavaScript代码,并且对多个script文件有顺序要求的
- async通常用于独立的脚本,对其他脚本,甚至DOM没有依赖的
断开连接:TCP 四次挥手
在渲染完成后,浏览器可能会继续加载页面中的其他资源,如异步加载的内容或者通过JavaScript生成的动态内容。
而在此过程中,如果没有其他资源需要加载,浏览器将与服务器之间的TCP连接断开。
简单理解
复制代码主动方:我已经关闭了向你那边的主动通道了,这是我最后一次给你发消息了,之后只能被动接收你的信息了
被动方:收到你通道关闭的信息
被动方:那我也告诉你,我这边向你的主动通道也关闭了
主动方:最后收到你关闭的信息,OK结束
断开连接,结束通讯
————————————————————————————————————————————————————————————————————————————
提出分手的可能是男生(客户端),也可能是女生(服务端)
主动方:分手吧,我不喜欢你了!
被动方:行,你等我忙完手上的工作我在收拾你!
被动方:我忙完了,分手就分手!
主动方:好,好聚好散,拜拜!
断开连接,结束通讯
详细分析
由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。
任何一方都可以在数据传送结束后发出连接释放的通知,所有主动发起关闭请求可以是客户端,也可以是服务端
这里我们假设是由客户端先主动发起关闭请求
- 第一次挥手:TCP客户进程会发送TCP连接释放报文段,并进入终止等待1(FIN-WAIT-1)状态。 FIN:终止位,表示断开TCP连接 TCP规定终止位FIN等于1的报文段即使不携带数据,也要消耗掉一个序号
- 第二次挥手:TCP服务器进程收到TCP连接释放报文段后,会发送一个普通的TCP确认报文段并进入关闭等待(CLOSE-WAIT)状态。 序号seq字段的值设置为v,与之前收到的TCP连接释放报文段中的确认号匹配 TCP客户进程收到TCP确认报文段后就进入终止等待2(FIN-WAIT-2)状态,等待TCP服务器进程发出的TCP连接释放报文段 这时的TCP连接属于半关闭状态,也就是TCP客户进程已经没有数据要发送了。但如果TCP服务器进程还有数据要发送,TCP客户进程仍要接收,也就是说从TCP服务器进程到TCP客户进程这个方向的连接并未关闭,这个状态可能要持续一段时间。
- 第三次挥手:TCP服务器进程发送TCP连接释放报文段 假定序号seq字段的值为w,这是因为在半关闭状态下,TCP服务器进程可能又发送了一些数据。 确认号ack字段的值为u+1,这是对之前收到的TCP连接释放报文段的重复确认。
- 第四次挥手:TCP服务器进程收到确定报文段后就进入关闭状态,而TCP客户进程还要经过2MSL后才能进入关闭状态。
之后断开连接,结束通讯
总结
- 浏览器先判断是否为合法的url格式,不合法则在搜索引擎中搜索
- 合法后,DNS解析会先判断缓存中是否有url的ip地址。
- 缓存的查询顺序是:浏览器缓存 -> 操作系统缓存(本地的hosts文件) -> 路由器缓存 -> 本地的DNS服务器缓存
- 在缓存中没有的情况,则向服务器发起请求查询ip地址。
- 查询IP地址的顺序是:根域名服务器 -> 顶级域名服务器 -> 权威域名服务器。直到查找到返回,并将其存储在缓存中下次使用
- TSP建立连接,也就是三次握手
- 第一次握手,携带建立连接请求SYN=1和随机序列seq=x
- 第二次握手,携带确定字段ACK=1、连接请求SYN=1、随机序列seq=y和ack为上一次握手的seq+1,就是x+1
- 第三次握手,携带确定字段ACK=1、ack=y+1、seq=x+1
- 如果是https,还有一个TLS四次握手
- 第一次握手,客户端向服务端发送 支持的协议版本 + 支持的加密方法 + 生成的随机数
- 第二次握手,服务端向客户端发送 证书 + 公钥 + 随机数
- 第三次握手前,客户端会先验证证书有没有过期、域名对不对、是否可信机构颁发的。
- 没有问题或者用户接受不受信的证书,浏览器会生成一个新的随机数
- 第三次握手,将之前的三个随机数通过一定的算法生成会话秘钥,之后的加密解密都是用这个秘钥
- 第四次握手,服务端收到回复,是用确定的加密方法进行解密,得到第三个随机数,使用同样的算法计算出会话秘钥
- 建立连接之后,浏览器发送http请求
- 请求报文由请求行、请求头、空行和请求体组成
- 服务器解析请求报文,返回响应报文
- 响应报文由响应行、响应头、空行和响应体组成,我们需要的html文件就在响应体中
- 浏览器拿到html文件并开始解析,构建dom tree。遇到css文件,下载并构建CSSOM tree。等到两者都构建完成之后,一起构建Render tree。然后进行布局和绘制
- 其中遇到了script标签,则停止构建dom tree,等下载完成之后才会继续构建dom tree
- 当资源传输完毕之后,TSP关闭连接,进行四次挥手的操作,其中四次挥手的操作客户端和服务器都可以发起
- 第一次挥手,携带断开连接的FIN=1、确定字段ACK=1、随机序列seq=u,ack=v
- 第二次挥手,携带确定字段ACK=1、随机序列seq=v,ack=u+1
- 第三次挥手,携带确定字段ACK=1、断开连接FIN=1、随机序列seq=w、ack=u+1
- 第四次挥手,携带确定字段ACK=1,随机序列seq=u+1,ack=w+1
- 等待2MSL后进入关闭状态
- 断开连接,结束通讯
作者:前端实习生鲸落
链接:https://juejin.cn/post/7279093851000242234