【第一章】前端基础
HTTP简要介绍
http:超文本传输协议,在客户端与服务端之间传输信息,客户端发送html,css给服务器,服务器返回源码给客户端;
https:是一种更安全的传输协议,在协议上加了一层密码,不容易被黑客攻击,更加安全。多用于支付页面,政府机构页面,公安局页面,银行……;
首先补充一下,http和https的区别,相比于http,https是基于ssl加密的http协议
简要概括:http2.0是基于1999年发布的http1.0之后的首次更新。
提升访问速度(可以对于,请求资源所需时间更少,访问速度更快,相比http1.0)
允许多路复用:多路复用允许同时通过单一的HTTP/2连接发送多重请求-响应信息。改善了:在http1.1中,浏览器客户端在同一时间,针对同一域名下的请求有一定数量限制(连接数量),超过限制会被阻塞。
二进制分帧:HTTP2.0会将所有的传输信息分割为更小的信息或者帧,并对他们进行二进制编码
首部压缩
服务器端推送
HTTP/1.1
报文格式如下
Request报文
Responese报文
http/1.1的问题
http协议早期为互联网的普及做出了巨大的贡献,构建了现代互联网的基础架构,但是由于协议制定的时间较早,在很多方面还是有着局限性,在互联网高速发展,信息爆炸的今天,难免有些捉襟见肘。主要体现在以下几个方面:
- 传输报文为ascii文本形式,对于http header不会进行压缩。这样对于可读性是比较友好,但对于计算机不太友好,此外传输效率较低
- 请求只能由客户端发起,不能由服务端发起。这种模式限制了一些主动推送或者有双工需求的使用场景,当然也有比如websocket之类的解决方案,但那严格来说已经不属于http协议的范畴了。
- 同步阻塞通讯:其实在http/1.1中已经默认使用了持久连接(persistent connection),可以做到多个请求复用同一个tcp连接,同时利用管道机制(pipelining),可以让请求同时在一个tcp连接上发送,但是http本质上还是一个
请求/响应
模型,服务端仍然需要按照请求的顺序依次回复,不能乱序回复。这样要是前面的回应特别慢,后面就会有许多请求排队等着。这称为“队头堵塞”(Head-of-line blocking)。 - 由于队头堵塞问题的存在,在客户端要下载大量资源的情况下,不得不和服务器建立多个TCP连接(大部分浏览器允许最多建立6个和指定服务器的持久连接),达到并发传输的效果,而众所周知,建立和销毁tcp连接的成本是非常高昂的(如果是https就更高),同时也增加了服务端的资源消耗。
基于以上的这些痛点,催生出了http/2。
HTTP/2协议介绍
二进制分层帧
HTTP/2 所有性能增强的核心在于新的二进制分帧层,它定义了如何封装 HTTP 消息并在客户端与服务器之间传输。
可以看到,http的语义都没有变化(包括各种动词、方法、标头),不同的是传输期间对它们的编码方式变了。HTTP/1.x 协议以换行符作为纯文本的分隔符,而 HTTP/2 将所有传输的信息分割为更小的消息和帧,并采用二进制格式对它们编码。原来的http header封入
HEADERS frame
,原来的http body封入DATA frame
。这样一来,客户端和服务器要互相理解,势必都要支持http/2的报文格式,由于引入了新的二进制分层帧的概念,这个协议并不向后兼容,这也是它叫做http/2而不是http/1.2 的根本原因。
数据流、消息和帧
新的二进制分帧机制改变了客户端与服务器之间交换数据的方式。 为了说明这个过程,我们需要了解 HTTP/2 的三个概念:
数据流:已建立的连接内的双向字节流,可以承载一条或多条消息。
消息:与逻辑请求或响应消息对应的完整的一系列帧。
帧:HTTP/2 通信的最小单位,每个帧都包含帧头,至少也会标识出当前帧所属的数据流。
这些概念的关系总结如下:所有通信都在一个 TCP 连接上完成,此连接可以承载任意数量的双向数据流。
每个数据流都有一个唯一的标识符和可选的优先级信息,用于承载双向消息。
每条消息都是一条逻辑 HTTP 消息(例如请求或响应),包含一个或多个帧。
帧是最小的通信单位,承载着特定类型的数据,例如 HTTP 标头、消息负载,等等。 来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。
简言之,HTTP/2 将 HTTP 协议通信分解为二进制编码帧的交换,这些帧对应着特定数据流中的消息。所有这些都在一个 TCP 连接内复用。这是 HTTP/2 协议所有其他功能和性能优化的基础。
请求与响应复用
在 HTTP/1.x 中,如果客户端要想发起多个并行请求以提升性能,则必须使用多个 TCP 连接(请参阅使用多个 TCP 连接)。这是 HTTP/1.x 交付模型的直接结果,该模型可以保证每个连接每次只交付一个响应(响应排队)。更糟糕的是,这种模型也会导致队首阻塞,从而造成底层 TCP 连接的效率低下。
HTTP/2 中新的二进制分帧层突破了这些限制,实现了完整的请求和响应复用:客户端和服务器可以将 HTTP 消息分解为互不依赖的帧,然后交错发送,最后再在另一端把它们重新组装起来。
快照捕捉了同一个连接内并行的多个数据流。客户端正在向服务器传输一个 DATA
帧(数据流 5),与此同时,服务器正向客户端交错发送数据流 1 和数据流 3 的一系列帧。因此,一个连接上同时有三个并行数据流。
将 HTTP 消息分解为独立的帧,交错发送,然后在另一端重新组装是 HTTP 2 最重要的一项增强。事实上,这个机制会在整个网络技术栈中引发一系列连锁反应,从而带来巨大的性能提升,让我们可以:
- 并行交错地发送多个请求,请求之间互不影响。
- 并行交错地发送多个响应,响应之间互不干扰。
- 使用一个连接并行发送多个请求和响应。
- 不必再为绕过 HTTP/1.x 限制而做很多工作(请参阅针对 HTTP/1.x 进行优化,例如级联文件、image sprites 和域名分片。
- 消除不必要的延迟和提高现有网络容量的利用率,从而减少页面加载时间。
- 等等…
HTTP/2 中的新二进制分帧层解决了 HTTP/1.x 中存在的队头阻塞问题,也消除了并行处理和发送请求及响应时对多个连接的依赖。结果,应用速度更快、开发更简单、部署成本更低。
数据流优先级
这个是http/2协议的一个高级功能。将 HTTP 消息分解为很多独立的帧之后,我们就可以复用多个数据流中的帧,客户端和服务器交错发送和传输这些帧的顺序就成为关键的性能决定因素。为了做到这一点,HTTP/2 标准允许每个数据流都有一个关联的权重和依赖关系:
可以向每个数据流分配一个介于 1 至 256 之间的整数。
每个数据流与其他数据流之间可以存在显式依赖关系。
数据流依赖关系和权重的组合让客户端可以构建和传递“优先级树”,表明它倾向于如何接收响应。反过来,服务器可以使用此信息通过控制 CPU、内存和其他资源的分配设定数据流处理的优先级,在资源数据可用之后,带宽分配可以确保将高优先级响应以最优方式传输至客户端。
HTTP/2 内的数据流依赖关系通过将另一个数据流的唯一标识符作为父项引用进行声明;如果忽略标识符,相应数据流将依赖于“根数据流”。声明数据流依赖关系指出,应尽可能先向父数据流分配资源,然后再向其依赖项分配资源。换句话说,“请先处理和传输响应 D,然后再处理和传输响应 C”。
共享相同父项的数据流(即,同级数据流)应按其权重比例分配资源。 例如,如果数据流 A 的权重为 12,其同级数据流 B 的权重为 4,那么要确定每个数据流应接收的资源比例,请执行以下操作:
- 将所有权重求和:4 + 12 = 16
- 将每个数据流权重除以总权重:A = 12/16, B = 4/16因此,数据流 A 应获得四分之三的可用资源,数据流 B 应获得四分之一的可用资源;数据流 B 获得的资源是数据流 A 所获资源的三分之一。我们来看一下上图中的其他几个动手示例:顺序为从左到右:
- 数据流 A 和数据流 B 都没有指定父依赖项,依赖于显式“根数据流”;A 的权重为 12,B 的权重为 4。因此,根据比例权重:数据流 B 获得的资源是 A 所获资源的三分之一。
- 数据流 D 依赖于根数据流;C 依赖于 D。因此,D 应先于 C 获得完整资源分配。权重不重要,因为 C 的依赖关系拥有更高的优先级。
- 数据流 D 应先于 C 获得完整资源分配;C 应先于 A 和 B 获得完整资源分配;数据流 B 获得的资源是 A 所获资源的三分之一。
- 数据流 D 应先于 E 和 C 获得完整资源分配;E 和 C 应先于 A 和 B 获得相同的资源分配;A 和 B 应基于其权重获得比例分配。
如上面的示例所示,数据流依赖关系和权重的组合明确表达了资源优先级,这是一种用于提升浏览性能的关键功能,网络中拥有多种资源类型,它们的依赖关系和权重各不相同(比如在一个网页上,我们应该先优先保障加载文本资源,然后再是图片和视频)。不仅如此,HTTP/2 协议还允许客户端随时更新这些优先级,进一步优化了浏览器性能。换句话说,我们可以根据用户互动和其他信号更改依赖关系和重新分配权重。
每个来源一个连接
这个是http/2协议所带来的重大性能提升。有了新的分帧机制后,HTTP/2 不再依赖多个 TCP 连接去并行复用数据流;每个数据流都拆分成很多帧,而这些帧可以交错,还可以分别设定优先级。因此,所有 HTTP/2 连接都是永久的,而且仅需要每个来源一个连接,随之带来诸多性能优势。
大多数 HTTP 传输都是短暂且急促的,而 TCP 则针对长时间的批量数据传输进行了优化。 通过重用相同的连接,HTTP/2 既可以更有效地利用每个 TCP 连接,也可以显著降低整体协议开销。不仅如此,使用更少的连接还可以减少占用的内存和处理空间,也可以缩短完整连接路径(即,客户端、可信中介和源服务器之间的路径)这降低了整体运行成本并提高了网络利用率和容量。 因此,迁移到 HTTP/2 不仅可以减少网络延迟,还有助于提高通量和降低运行成本。
连接数量减少对提升 HTTPS 部署的性能来说是一项特别重要的功能:众所周知建立基于TLS的http连接非常耗时,http/2可以减少开销较大的 TLS 连接数、提升会话重用率,以及从整体上减少所需的客户端和服务器资源。
流控制
流控制是一种阻止发送方向接收方发送大量数据的机制,以免超出后者的需求或处理能力:发送方可能非常繁忙、处于较高的负载之下,也可能仅仅希望为特定数据流分配固定量的资源。例如,客户端可能请求了一个具有较高优先级的大型视频流,但是用户已经暂停视频,客户端现在希望暂停或限制从服务器的传输,以免提取和缓冲不必要的数据。再比如,一个代理服务器可能具有较快的下游连接和较慢的上游连接,并且也希望调节下游连接传输数据的速度以匹配上游连接的速度来控制其资源利用率;等等。
上述要求会让您想到 TCP 流控制吗?您应当想到这一点;因为问题基本相同(请参阅流控制)。不过,由于 HTTP/2 数据流在一个 TCP 连接内复用,TCP 流控制既不够精细,也无法提供必要的应用级 API 来调节各个数据流的传输。为了解决这一问题,HTTP/2 提供了一组简单的构建块,这些构建块允许客户端和服务器实现其自己的数据流和连接级流控制:
- 流控制具有方向性。每个接收方都可以根据自身需要选择为每个数据流和整个连接设置任意的窗口大小。
- 流控制基于信用。每个接收方都可以公布其初始连接和数据流流控制窗口(以字节为单位),每当发送方发出
DATA
帧时都会减小,在接收方发出WINDOW_UPDATE
帧时增大。 - 流控制无法停用。建立 HTTP/2 连接后,客户端将与服务器交换
SETTINGS
帧,这会在两个方向上设置流控制窗口。流控制窗口的默认值设为 65,535 字节,但是接收方可以设置一个较大的最大窗口大小(2^31-1
字节),并在接收到任意数据时通过发送WINDOW_UPDATE
帧来维持这一大小。 - 流控制为逐跃点控制,而非端到端控制。即,可信中介可以使用它来控制资源使用,以及基于自身条件和启发式算法实现资源分配机制。
HTTP/2 未指定任何特定算法来实现流控制。不过,它提供了简单的构建块并推迟了客户端和服务器实现,可以实现自定义策略来调节资源使用和分配,以及实现新传输能力,同时提升网络应用的实际性能和感知性能(请参阅速度、性能和人类感知)。
例如,应用层流控制允许浏览器仅提取一部分特定资源,通过将数据流流控制窗口减小为零来暂停提取,稍后再行恢复。换句话说,它允许浏览器提取图像预览或首次扫描结果,进行显示并允许其他高优先级提取继续,然后在更关键的资源完成加载后恢复提取。
服务器推送
之前介绍过,HTTP/1.1无法从服务器主动推送信息给客户端,而这是HTTP/2 新增的另一个强大的新功能,服务器可以对一个客户端请求发送多个响应。 换句话说,除了对最初请求的响应外,服务器还可以向客户端推送额外资源,而无需客户端明确地请求。
HTTP/2 打破了严格的请求-响应语义,支持一对多和服务器发起的推送工作流,在浏览器内外开启了全新的互动可能性。这是一项重要功能,对我们思考协议、协议用途和使用方式具有重要的长期影响。
为什么在浏览器中需要一种此类机制呢?一个典型的网络应用包含多种资源,客户端需要检查服务器提供的文档才能逐个找到它们。那为什么不让服务器提前推送这些资源,从而减少额外的延迟时间呢?服务器已经知道客户端下一步要请求什么资源,这时候服务器推送即可派上用场。
事实上,如果您在网页中内联过 CSS、JavaScript,或者通过数据 URI 内联过其他资产(请参阅资源内联),那么您就已经亲身体验过服务器推送了。对于将资源手动内联到文档中的过程,我们实际上是在将资源推送给客户端,而不是等待客户端请求。使用 HTTP/2,我们不仅可以实现相同结果,还会获得其他性能优势。 推送资源可以进行以下处理:
- 由客户端缓存
- 在不同页面之间重用
- 与其他资源一起复用
- 由服务器设定优先级
- 被客户端拒绝
PUSH_PROMISE 101
所有服务器推送数据流都由 PUSH_PROMISE
帧发起,表明了服务器向客户端推送所述资源的意图,并且需要先于请求推送资源的响应数据传输。这种传输顺序非常重要:客户端需要了解服务器打算推送哪些资源,以免为这些资源创建重复请求。满足此要求的最简单策略是先于父响应(即,DATA
帧)发送所有 PUSH_PROMISE
帧,其中包含所承诺资源的 HTTP 标头。
在客户端接收到 PUSH_PROMISE
帧后,它可以根据自身情况选择拒绝数据流(通过 RST_STREAM
帧)。 (如果资源已经位于缓存中,可能会发生这种情况。) 这是一个相对于 HTTP/1.x 的重要提升。 相比之下,使用资源内联(一种受欢迎的 HTTP/1.x“优化”)等同于“强制推送”:客户端无法选择拒绝、取消或单独处理内联的资源。
使用 HTTP/2,客户端仍然完全掌控服务器推送的使用方式。客户端可以限制并行推送的数据流数量;调整初始的流控制窗口以控制在数据流首次打开时推送的数据量;或完全停用服务器推送。这些优先级在 HTTP/2 连接开始时通过 SETTINGS
帧传输,可能随时更新。
推送的每个资源都是一个数据流,与内嵌资源不同,客户端可以对推送的资源逐一复用、设定优先级和处理。 浏览器强制执行的唯一安全限制是,推送的资源必须符合原点相同这一政策:服务器对所提供内容必须具有权威性。
标头压缩
每个 HTTP 传输都承载一组标头,这些标头说明了传输的资源及其属性。 在 HTTP/1.x 中,此元数据始终以纯文本形式,通常会给每个传输增加 500–800 字节的开销。如果使用 HTTP Cookie,增加的开销有时会达到上千字节。(请参阅测量和控制协议开销。)为了减少此开销和提升性能,HTTP/2 使用 HPACK 压缩格式压缩请求和响应标头元数据,这种格式采用两种简单但是强大的技术:
- 这种格式支持通过静态 Huffman 代码对传输的标头字段进行编码,从而减小了各个传输的大小。
- 这种格式要求客户端和服务器同时维护和更新一个包含之前见过的标头字段的索引列表(换句话说,它可以建立一个共享的压缩上下文),此列表随后会用作参考,对之前传输的值进行有效编码。
利用 Huffman 编码,可以在传输时对各个值进行压缩,而利用之前传输值的索引列表,我们可以通过传输索引值的方式对重复值进行编码,索引值可用于有效查询和重构完整的标头键值对。
HPACK 的安全性和性能
早期版本的 HTTP/2 和 SPDY 使用 zlib(带有一个自定义字典)压缩所有 HTTP 标头。 这种方式可以将所传输标头数据的大小减小 85% - 88%,显著减少了页面加载时间延迟:
在带宽较低的 DSL 链路中,上行链路速度仅有 375 Kbps,仅压缩请求标头就显著减少了特定网站(即,发出大量资源请求的网站)的页面加载时间。 我们发现,仅仅由于标头压缩,页面加载时间就减少了 45 - 1142 毫秒。(SPDY 白皮书,chromium.org)
然而,2012 年夏天,出现了针对 TLS 和 SPDY 压缩算法的“犯罪”安全攻击,此攻击会导致会话被劫持。 于是,zlib 压缩算法被 HPACK 替代,后者经过专门设计,可以解决发现的安全问题、实现起来也更高效和简单,当然,可以对 HTTP 标头元数据进行良好压缩。
HTTP缓存机制(博客)
缓存分为两种:强缓存和协商缓存,根据响应的header内容来决定。
获取资源形式 | 状态码 | 发送请求到服务器 | |
---|---|---|---|
强缓存 | 从缓存取 | 200(from cache) | 否,直接从缓存取 |
协商缓存 | 从缓存取 | 304(not modified) | 是,通过服务器来告知缓存是否可用 |
强缓存相关字段有expires,cache-control
。如果cache-control与expires同时存在的话,cache-control的优先级高于expires。
协商缓存相关字段有Last-Modified/If-Modified-Since,Etag/If-None-Match
Etag/If-None-Match
Etag/If-None-Match也要配合Cache-Control使用。
Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器觉得)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。
If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match(Etag的值)。web服务器收到请求后发现有头If-None-Match则与被请求资源的相应校验串进行比对,决定返回200或304。
Last-Modified/If-Modified-Since
Last-Modified/If-Modified-Since要配合Cache-Control使用。
Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。
既生Last-Modified何生Etag?
你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
1.Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
2.如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存
3.有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
启用Web缓存
了解了Web缓存的基本原理和重要性,接下来的问题就是如何在项目里使用。
- 对于使用nginx或者apache做为Web前端的系统,有相应的指令达成目的,资料很多,比如可以参考NGINX下配置CACHE-CONTROL头部。
- 对于使用高版本Tomcat的项目,没有必要自造轮子,官方实现的ExpiresFilter已经可以满足日常的使用,具体方法可以参考ExpiresFilter官方文档和Tomcat性能调优 通过ExpiresFilter设置资源缓存。
- 对于使用低版本Tomcat的项目来说,虽然没有官方的过滤器可用,但可以自定义过滤器来实现缓存,具体方法可以参考tomcat中Cache-Control 的配置和使用Cache-Control和gzip提升tomcat应用性能(整理),代码和配置都比较简单,很好理解。
cookie和session的区别,localstorage和sessionstorage的区别
https://www.cnblogs.com/cencenyue/p/7604651.html
Cookie和session都可用来存储用户信息,cookie存放于客户端,session存放于服务器端,因为cookie存放于客户端有可能被窃取,所以cookie一般用来存放不敏感的信息,比如用户设置的网站主题,敏感的信息用session存储,比如用户的登陆信息,session可以存放于文件,数据库,内存中都可以,cookie可以服务器端响应的时候设置,也可以客户端通过JS设置cookie会在请求时在http首部发送给客户端,cookie一般在客户端有大小限制,一般为4K,
下面从几个方向区分一下cookie,localstorage,sessionstorage的区别
1、生命周期:
Cookie:可设置失效时间,否则默认为关闭浏览器后失效
Localstorage:除非被手动清除,否则永久保存
Sessionstorage:仅在当前网页会话下有效,关闭页面或浏览器后就会被清除
2、存放数据:
Cookie:4k左右
Localstorage和sessionstorage:可以保存5M的信息
3、http请求:
Cookie:每次都会携带在http头中,如果使用cookie保存过多数据会带来性能问题
其他两个:仅在客户端即浏览器中保存,不参与和服务器的通信
4、易用性:
Cookie:需要程序员自己封装,原生的cookie接口不友好
其他两个:即可采用原生接口,亦可再次封装
5、应用场景:
从安全性来说,因为每次http请求都回携带cookie信息,这样子浪费了带宽,所以cookie应该尽可能的少用,此外cookie还需要指定作用域,不可以跨域调用,限制很多,但是用户识别用户登陆来说,cookie还是比storage好用,其他情况下可以用storage,localstorage可以用来在页面传递参数,sessionstorage可以用来保存一些临时的数据,防止用户刷新页面后丢失了一些参数
1 | /** |
HTTPS协议原理
通信过程
HTTPS在传输的过程中会涉及到三个密钥:
服务器端的公钥和私钥,用来进行非对称加密
客户端生成的随机密钥,用来进行对称加密
一个HTTPS请求实际上包含了两次HTTP传输,可以细分为8步。
客户端向服务器发起HTTPS请求,连接到服务器的443端口。
服务器端有一个密钥对,即公钥和私钥,是用来进行非对称加密使用的,服务器端保存着私钥,不能将其泄露,公钥可以发送给任何人。
服务器将自己的公钥发送给客户端。
客户端收到服务器端的公钥之后,会对公钥进行检查,验证其合法性,如果发现发现公钥有问题,那么HTTPS传输就无法继续。严格的说,这里应该是验证服务器发送的数字证书的合法性,关于客户端如何验证数字证书的合法性,下文会进行说明。如果公钥合格,那么客户端会生成一个随机值,这个随机值就是用于进行对称加密的密钥,我们将该密钥称之为client key,即客户端密钥,这样在概念上和服务器端的密钥容易进行区分。然后用服务器的公钥对客户端密钥进行非对称加密,这样客户端密钥就变成密文了,至此,HTTPS中的第一次HTTP请求结束。
客户端会发起HTTPS中的第二个HTTP请求,将加密之后的客户端密钥发送给服务器。
服务器接收到客户端发来的密文之后,会用自己的私钥对其进行非对称解密,解密之后的明文就是客户端密钥,然后用客户端密钥对数据进行对称加密,这样数据就变成了密文。
然后服务器将加密后的密文发送给客户端。
客户端收到服务器发送来的密文,用客户端密钥对其进行对称解密,得到服务器发送的数据。这样HTTPS中的第二个HTTP请求结束,整个HTTPS传输完成。
对称加密和非对称加密介绍和区别
什么是对称加密技术?
对称加密采用了对称密码编码技术,它的特点是文件加密和解密使用相同的密钥加密
也就是密钥也可以用作解密密钥,这种方法在密码学中叫做对称加密算法,对称加密算法使用起来简单快捷,密钥较短,且破译困难,除了数据加密标准(DES),另一个对称密钥加密系统是国际数据加密算法(IDEA),它比DES的加密性好,而且对计算机功能要求也没有那么高
对称加密算法在电子商务交易过程中存在几个问题:
1、要求提供一条安全的渠道使通讯双方在首次通讯时协商一个共同的密钥。直接的面对面协商可能是不现实而且难于实施的,所以双方可能需要借助于邮件和电话等其它相对不够安全的手段来进行协商;
2、密钥的数目难于管理。因为对于每一个合作者都需要使用不同的密钥,很难适应开放社会中大量的信息交流;
3、对称加密算法一般不能提供信息完整性的鉴别。它无法验证发送者和接受者的身份;
4、对称密钥的管理和分发工作是一件具有潜在危险的和烦琐的过程。对称加密是基于共同保守秘密来实现的,采用对称加密技术的贸易双方必须保证采用的是相同的密钥,保证彼此密钥的交换是安全可靠的,同时还要设定防止密钥泄密和更改密钥的程序。
假设两个用户需要使用对称加密方法加密然后交换数据,则用户最少需要2个密钥并交换使用,如果企业内用户有n个,则整个企业共需要n×(n-1) 个密钥,密钥的生成和分发将成为企业信息部门的恶梦。
常见的对称加密算法有DES、3DES、Blowfish、IDEA、RC4、RC5、RC6和AES
什么是非对称加密技术
与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。
公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。甲方只能用其专用密钥解密由其公用密钥加密后的任何信息。
非对称加密的典型应用是数字签名。
常见的非对称加密算法有:RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用)
Hash算法(摘要算法)
Hash算法特别的地方在于它是一种单向算法,用户可以通过hash算法对目标信息生成一段特定长度的唯一hash值,却不能通过这个hash值重新获得目标信息。因此Hash算法常用在不可还原的密码存储、信息完整性校验等。
常见的Hash算法有MD2、MD4、MD5、HAVAL、SHA
Springboot中开启https服务
application.yml
中的配置
1 | server: |
TCP
TCP、UDP以及TCP滑窗,它们的区别[转]
滑窗
- 上面的工作方式中,发送方保持发送->等待ACK->发送->等待ACK…的单线工作方式,这样的工作方式叫做stop-and-wait。stop-and-wait虽然实现了TCP通信的可靠性,但同时牺牲了网络通信的效率。在等待ACK的时间段内,我们的网络都处于闲置(idle)状态。我们希望有一种方式,可以同时发送出多个片段。然而如果同时发出多个片段,那么由于IP包传送是无次序的,有可能会生成乱序片段(out-of-order),也就是后发出的片段先到达。在stop-and-wait的工作方式下,乱序片段完全被拒绝,这也很不效率。毕竟,乱序片段只是提前到达的片段。我们可以在缓存中先存放它,等到它之前的片段补充完毕,再将它缀在后面。然而,如果一个乱序片段实在是太过提前(太“乱”了),该片段将长时间占用缓存。我们需要一种折中的方法来解决该问题:利用缓存保留一些“不那么乱”的片段,期望能在段时间内补充上之前的片段(暂不处理,但发送相应的ACK);对于“乱”的比较厉害的片段,则将它们拒绝(不处理,也不发送对应的ACK)。
- 滑窗(sliding window)被同时应用于接收方和发送方,以解决以上问题。发送方和接收方各有一个滑窗。当片段位于滑窗中时,表示TCP正在处理该片段。滑窗中可以有多个片段,也就是可以同时处理多个片段。滑窗越大,越大的滑窗同时处理的片段数目越多(当然,计算机也必须分配出更多的缓存供滑窗使用)。
- 我们假设一个可以容纳三个片段的滑窗,并假设片段从左向右排列。对于发送方来说,滑窗的左侧为已发送并已ACK过的片段序列,滑窗右侧是尚未发送的片段序列。滑窗中的片段(比如片段5,6,7)被发送出去,并等待相应的ACK。如果收到片段5的ACK,滑窗将向右移动。这样,新的片段从右侧进入滑窗内,被发送出去,并进入等待状态。在接收到片段5的ACK之前,滑窗不会移动,即使已经收到了片段6和7的ACK。这样,就保证了滑窗左侧的序列是已经发送的、接收到ACK的、符合顺序的片段序列。
- 对于接收方来说,滑窗的左侧是已经正确收到并ACK回复过的片段(比如片段1,2,3,4),也就是正确接收到的文本流。滑窗中是期望接收的片段(比如片段5, 6, 7)。同样,如果片段6,7先到达,那么滑窗不会移动。如果片段5先到达,那么滑窗会向右移动,以等待接收新的片段。如果出现滑窗之外的片段,比如片段9,那么滑窗将拒绝接收。
- 利用滑窗,我们一定程度上实现了对乱序数据的缓存。但是,过于乱序的数据依然会被拒绝。我们之前说的stop-and-wait的工作方式,相当于发送方和接收方的滑窗都只能容纳一个片段。
拥塞控制的原理
一、拥塞控制的一般原理
1、产生拥塞的原因:在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就会变坏。即对资源的需求
可用资源
注意拥塞控制与流量控制的区别:拥塞控制是防止过多的数据注入网络中,使得网络中路由器或链路不致过载,有一个前提是,网络能够承受现有的网络负荷,是一个全局性过程;流量控制是指点对点通信的控制,做的是抑制发送端发送数据的速率,便于接收端来得及接收。
2、拥塞控制是一个动态的过程,通常使用网络负载(单位时间输入给网络的分组数量)和吞吐量(单位时间从网络输出的分组的数量)来进行比较:
当网络负载 > 吞吐量,网络进入拥塞,严重甚至会产生死锁。
二、TCP拥塞控制方法
主要有四种算法:慢开始、拥塞避免、快重传、快恢复。
1、慢开始和拥塞避免
基于窗口的拥塞控制,在发送方维护一个拥塞窗口(cwnd),大小等于发送窗口,通过出现了超时来判断网络出现拥塞。慢开始的思路是一开始发送方发送一个字节,在收到接收方的确认,然后发送的字节数量增大一倍(也就是按照指数增长的速率),从小到大逐步增大cwnd,直到cwnd 达到慢开始门限(ssthresh),停止慢开始算法,使用拥塞避免算法,拥塞避免算法思路是增长速率变为线性增长,也就是每经过一个往返时间RTT就把发送方的cwnd加1,所以综上:
当cwnd < ssthresh ,使用慢开始算法;
当cwnd = ssthresh,可以使用慢开始算法,也可以使用拥塞算法;
当cwnd > ssthresh,使用拥塞算法;
2、快重传和快恢复
通过上面两个算法可以使得网络传输速率一直增大,直到出现超时,这时候需要将cwnd重新调整到1个字节开始,使用慢开始算法,同时需要将慢开始门限ssthresh调整为cwnd(超时点)的一半,继续执行慢开始、拥塞避免算法。如果收到3-ACK(发送方一连接收到3个对同一个报文段的重复确认),这种可能的情况是,并不是发生了拥塞,可能是报文丢失,所以发送方不执行慢开始算法,直接使用快重传算法,立即发送缺失的报文段。同时执行快恢复算法,将门限值(ssthresh)调整为此时cwnd的一半,并执行拥塞避免算法。
三、总结
从宏观上看,在连接建立开始到连接终止这个过程中,TCP传输的速率需要流量控制和拥塞控制,共同调整发送方的窗口,所以最终发送方的发送窗口的上限值为Min(rwnd,cwnd)。而拥塞控制,主要调控发送方的网络负载和吞吐量的相对大小,从慢开始(指数增长,增长率大)、拥塞避免算法(线性增长,增长率不变)一直增大速率,期间算法切换条件是慢开始门限值(ssthresh),若此增大期间出现超时,都需要将ssthresh = cwnd / 2, cwnd = 1(之后执行慢开始算法);若此增大期间出现3-ACK,则ssthresh=cwnd / 2, cwnd = ssthresh(之后执行拥塞避免算法),直至到连接终止结束。
思考一个问题:ssthresh是不是从一开始设立后只会减小,不会增大?
【第二章】前端核心
Javascript
事件委托机制
JSDOM
事件流存在如下三个阶段:- 事件捕获阶段
- 处于目标阶段
- 事件冒泡阶段
JSDOM
标准事件流的触发的先后顺序为:先捕获再冒泡,点击DOM
节点时,事件传播顺序:事件捕获阶段,从上往下传播,然后到达事件目标节点,最后是冒泡阶段,从下往上传播DOM
节点添加事件监听方法addEventListener
,中参数capture可以指定该监听是添加在事件捕获阶段还是事件冒泡阶段,为false是事件冒泡,为true是事件捕获,并非所有的事件都支持冒泡,比如focus,blur等等
,我们可以通过event.bubbles
来判断addEventListener(type,listener,useCapture)
- type: 必须,String类型,事件类型
- listener: 必须,函数体或者JS方法
- useCapture: 可选,boolean类型。指定事件是否发生在捕获阶段。默认为false,事件发生在冒泡阶段
- 事件模型有三个常用方法:
event.stopPropagation
:阻止捕获和冒泡阶段中,当前事件的进一步传播,event.stopImmediatePropagetion
,阻止调用相同事件的其他侦听器,event.preventDefault
,取消该事件(假如事件是可取消的)而不停止事件的进一步传播,- event.target:指向触发事件的元素,在事件冒泡过程中这个值不变
- event.currentTarget = this,时间帮顶的当前元素,只有被点击时目标元素的target才会等于currentTarget,
- 最后,对于执行顺序的问题,如果DOM节点同时绑定了两个事件监听函数,一个用于捕获,一个用于冒泡,那么两个事件的执行顺序真的是先捕获在冒泡吗,答案是否定的,绑定在被点击元素的事件是按照代码添加顺序执行的,其他函数是先捕获再冒泡
对js原型的理解
我们大概介绍了原型中容易混淆的问题,主要有以下几方面:
- 所有函数都有一个属性
prototype
,这就是我们指的原型,他的初始值是一个空的对象 - 你可以原型对象添加属性和方法,甚至直接用另一个对象替换他
- 当你用构造函数new出一个对象之后,这个对象可以访问构造函数的原型对象的属性和方法
- 对象的自身属性搜索的优先级比原型的属性要高
proto
属性的神秘连接及其同prototype
的区别prototype
使用中的陷阱- 在我们完全替换掉原型对象的时候,原型会失去实时性,同时原型的构造函数属性不可靠,不是理论上应该的值
- 所以我们切记在替换掉原型对象之后,切记重新设置
constructor.prototype
JS实现跨域
JSONP
:通过动态创建script,再请求一个带参网址实现跨域通信。document.domain + iframe
跨域:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。location.hash + iframe
跨域:a欲与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash
传值,相同域之间直接js访问来通信。window.name + iframe
跨域:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name
从外域传递到本地域。postMessage
跨域:可以跨域操作的window属性之一。CORS:服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求,前后端都需要设置。
Vue框架
axios设置
1
axios.defaults.withCredentials = true
vue-resource设置
1
Vue.http.options.credentials = true
Java后台
1
2
3
4
5
6
7
8
9
10
11
12
13/*
* 导入包:import javax.servlet.http.HttpServletResponse;
* 接口参数中定义:HttpServletResponse response
*/
// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
代理跨域:启一个代理服务器,实现数据的转发(
nginx
)NodeJS中间件处理跨域
Vue
框架的跨域(1次跨域)利用
node + webpack + webpack-dev-server
代理接口跨域。在开发环境下,由于vue
渲染服务和接口代理服务都是webpack-dev-server
同一个,所以页面与代理接口之间不再跨域,无须设置headers
跨域信息了。webpack.config.js
部分配置:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16module.exports = {
entry: {},
module: {},
...
devServer: {
historyApiFallback: true,
proxy: [{
context: '/login',
target: 'http://www.domain2.com:8080', // 代理跨域目标接口
changeOrigin: true,
secure: false, // 当代理某些https服务报错时用
cookieDomainRewrite: 'www.domain1.com' // 可以为false,表示不修改
}],
noInfo: true
}
}
服务器推送
Vue+Java 通过websocket实现服务器与客户端双向通信
1 | // JS |
相关文章:【VUE+SpringBoot+Websocket实现前后端通信案例分享】
this指向
默认绑定:全局环境中,this默认绑定到window。
隐式绑定:一般地,被直接对象所包含的函数调用时,也称为方法调用,this隐式绑定到该直接对象。
隐式丢失:隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到window。显式绑定:通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定。
new绑定:如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。对于this绑定来说,称为new绑定。
【1】构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值。
【2】如果构造函数使用return语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果。
【3】如果构造函数显式地使用return语句返回一个对象,那么调用表达式的值就是这个对象。
setTimeout和Promise的执行顺序
首先我们来看这样一道题:
1 | setTimeout(function() { |
输出答案为2 10 3 5 4 1
要先弄清楚setTimeout(fun,0)何时执行,promise何时执行,then何时执行
setTimeout这种异步操作的回调,只有主线程中没有执行任何同步代码的前提下,才会执行异步回调,而setTimeout(fun,0)表示立刻执行,也就是用来改变任务的执行顺序,要求浏览器尽可能快的进行回调
promise何时执行,由上图可知promise新建后立即执行,所以promise构造函数里代码同步执行的,
then方法指向的回调将在当前脚本所有同步任务执行完成后执行,
那么then为什么比setTimeout执行的早呢,因为setTimeout(fun,0)不是真的立即执行,
经过测试得出结论:执行顺序为:同步执行的代码 → promise.then → setTimeout
JS的垃圾回收机制
GC(garbage collection),GC执行时,中断代码,停止其他操作,遍历所有对象,对于不可访问的对象进行回收,在V8引擎中使用两种优化方法,
分代回收
增量GC,目的是通过对象的使用频率,存在时长来区分新生代和老生代对象,多回收新生代区,少回收老生代区,减少每次遍历的时间,从而减少GC的耗时
回收方法:
- 引用计次,当对象被引用的次数为零时进行回收,但是循环引用时,两个对象都至少被引用了一次,因此导致内存泄漏,
- 标记清除
NodeJS
Node中的Event Loop
1 |
|
Vue
vue的双向绑定原理及实现
vue
数据双向绑定是通过Object.defineProperty()
数据劫持,结合发布者-订阅者模式的方式来实现的
实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
webpack
webpack
的配置
config/index.js
文件中
1 | const path = require('path'); |
从上面我们可以看到,webpack配置中需要理解几个核心的概念Entry
、Output
、Loaders
、Plugins
、 Chunk
- Entry:指定webpack开始构建的入口模块,从该模块开始构建并计算出直接或间接依赖的模块或者库
- Output:告诉webpack如何命名输出的文件以及输出的目录
- Loaders:由于webpack只能处理javascript,所以我们需要对一些非js文件处理成webpack能够处理的模块,比如sass文件
- Plugins:
Loaders
将各类型的文件处理成webpack能够处理的模块,plugins
有着很强的能力。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。但也是最复杂的一个。比如对js文件进行压缩优化的UglifyJsPlugin
插件 - Chunk:coding split的产物,我们可以对一些代码打包成一个单独的chunk,比如某些公共模块,去重,更好的利用缓存。或者按需加载某些功能模块,优化加载时间。在webpack3及以前我们都利用
CommonsChunkPlugin
将一些公共代码分割成一个chunk,实现单独加载。在webpack4 中CommonsChunkPlugin
被废弃,使用SplitChunksPlugin
HTML
布局
grid布局(博客)
【第三章】一些面试常见问题
当在浏览器输入url,向服务器发送请求,浏览器都做了些什么?
http事务:从浏览器传给服务器,服务器反回内容给浏览器,这一个完整的过程就叫做http的一个事务。
1、http请求阶段:
1)浏览器把url发送给DNS服务器;
2)DNS服务器会根据IP找到对应的服务器;
3)服务器接收到请求,客户端和服务器已经产生了连接;
2、http响应阶段:
4)服务器接收到请求后,根据路径,找到相应的项目;
5)服务器找到之后,服务器立即把一些响应信息放在响应头中,通过http发送给客户端,同时进行数据整理;
6)把整理出来的数据,通过http发送给客户端,直到客户端接收完毕;
3、浏览器渲染阶段:
7)浏览器拿到从服务器传输过来的数据文件;
8)先遍历HTML,形成DOM树;
9)代码从上到下解析,形成CSS树;
10)DOM树和CSS树重新组成render树;
11)浏览器进行描绘和渲染;
http的三次握手和四次挥手
浏览器在给服,务器传输数据之前,有三次握手,握手成功之后,才可以传输数据
1、浏览器需要先发送SYN码,客户端请求和服务器建立连接;
2、服务器接收到SYN码,再发送给客户端SYN+ACK码,我可以建立连接;
3、客户端接收到ACK码,验证这个ACK是否正确,如果正确则客户端和服务端则建立起数据连接;双方的数据发送通道都将开启;
四次挥手:
1、当客户端无数据要传输了,会发送FIN码告诉服务器,我发送完毕了;
2、当服务端接收完毕后,告诉客户端ACK码,告诉客户端你可以把数据通道关闭了;
3、当服务器发送完毕之后,也会发送FIN码,告诉浏览器,数据发送完毕;
4、当客户端接收完毕 之后,同样发送ACK码,告诉服务器,数据接收完毕,你可以关闭;
三次握手和四次挥手的好处:确保数据的安全和完整
响应头:服务器会告诉浏览器数据的长度,浏览器数据长度和响应头数据长度相同,说明数据已经接收完毕了。
get 与 post的区别?application json 与form表单的区别?
可以看到,POST请求会发送多少次TCP请求视发送内容大小和客户端特定协议而定,内容少则会跟header在一起包装成一个segment发送,反之则会将消息主体分多个TCP包发送出去
- 因为POST请求的协议并没有规定数据必须使用什么编码方式,而数据发送出去,还要服务器解析成功才行。服务器则通常根据请求头里的Content-Type字段来获知消息是以什么方式编码,再以对应方式解析。而有的接口服务器则不能解析某些编码方式的数据。因此需要对Content-Type进行设置。
- application/json这个Content-Type作为响应头大家肯定不陌生。实际上, 现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的JSON字符串。 由于JSON规范的流行,除了低版本IE之外的各大浏览器都原生支持JSON.stringify, 服务端语言也都有处理JSON的函数,使用JSON不会遇上什么麻烦。angular中默认的就是这个格式
- application/x-www-form-urlencoded这应该是最常见的POST提交数据的方式了。浏览器的原生form表单,如果不设置enctype属性, 那么最终就会以application/x-www-form-urlencoded方式提交数据。请求类似于下面这样( 无关的请求头在本文中都省略掉了):POST http://www.example.com HTTP/1.1 Content-Type: application/x-www-form-urlencoded;charset=utf-8 title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3首先,Content-Type被指定为application/x-www-form-urlencoded; 其次,提交的数据按照key1=val1&key2=val2的方式进行编码,key和val都进行了URL转码。 大部分服务端语言都对这种方式有很好的支持。
防抖节流
函数防抖(debounce
)
当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。如下图,持续触发scroll事件时,并不执行handle函数,当1000毫秒内没有触发scroll事件时,才会延时触发scroll事件。
防抖debounce
代码:
1 | // 防抖 |
函数节流(throttle
)
当持续触发事件时,保证一定时间段内只调用一次事件处理函数。节流通俗解释就比如我们水龙头放水,阀门一打开,水哗哗的往下流,秉着勤俭节约的优良传统美德,我们要把水龙头关小点,最好是如我们心意按照一定规律在某个时间间隔内一滴一滴的往下滴。如下图,持续触发scroll事件时,并不立即执行handle函数,每隔1000毫秒才会执行一次handle函数。
函数节流主要有两种实现方法:时间戳和定时器。接下来分别用两种方法实现throttle~
节流throttle代码(时间戳):
1 | var throttle = function(func, delay) { |
当高频事件触发时,第一次会立即执行(给scroll事件绑定函数与真正触发事件的间隔一般大于delay,如果你非要在网页加载1000毫秒以内就去滚动网页的话,我也没办法o(╥﹏╥)o),而后再怎么频繁地触发事件,也都是每delay时间才执行一次。而当最后一次事件触发完毕后,事件也不会再被执行了 (最后一次触发事件与倒数第二次触发事件的间隔小于delay,为什么小于呢?因为大于就不叫高频了呀(╹▽╹))。
节流throttle代码(定时器):
1 | // 节流throttle代码(定时器): |
当触发事件的时候,我们设置一个定时器,再次触发事件的时候,如果定时器存在,就不执行,直到delay时间后,定时器执行执行函数,并且清空定时器,这样就可以设置下个定时器。当第一次触发事件时,不会立即执行函数,而是在delay秒后才执行。而后再怎么频繁触发事件,也都是每delay时间才执行一次。当最后一次停止触发后,由于定时器的delay延迟,可能还会执行一次函数。
节流中用时间戳或定时器都是可以的。更精确地,可以用时间戳+定时器,当第一次触发事件时马上执行事件处理函数,最后一次触发事件后也还会执行一次事件处理函数。
节流throttle代码(时间戳+定时器):
1 | // 节流throttle代码(时间戳+定时器): |
总结
- 函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
- 函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。
- 区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。
Chrome打开一个页面需要启动多少进程
浏览器从关闭进行启动,然后新开1个页面至少需要1个网络进程、1个浏览器进程,一个GPU进程以及1个渲染进程,共4个进程;后续在新开标签页,浏览器、网络进程、GPU进程是共享的不会重新启动,如果2个也买你属于同一个站点的化,并且从a页面中打开的b页面,那么他们也会共用一个渲染进程,否则新开一个渲染进程
最新的Chrome浏览器包括:1个浏览器主进程(Browser)、1个GPU进程、一个网络(NetWork)进程和多个插件进程。
浏览器进程:主要负责界面显示、用户交互、子进程管理,同时提供存储功能;
渲染进程:核心人物是将HTML、CSS和JavaScript引擎V8都是及逆行在该进程中,漠然情况下,Chrome会为每个Ta标签创建一个渲染进程。出于安全考虑;徐然进程都是运行在沙箱模式下。
GPU进程:其实,Chrome刚开始发布的时候是没有GPU进程的。而GPU的使用初衷是为了实现3DCSS的效果,只是随后网页、Chrome的UI界面都选择采取GPU来绘制,这使得GPU成为浏览器普遍的需求。最后,Chrome在奇多进程架构上也引入了GPU进程。
网络进程:主要负责网页的网络资源加载,之前是作为一个模块运行在浏览器进程在里面的,直至最近才独立出来,成为一个单独的进程。
插件进程:主要是负责插件的运行,因插件容易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响