1.从url输出到页面显示发生啦什么
1.http协议
2.dns查找
3.html解析转成dom树
4.渲染过程是重点
答:浏览器有个ui线程,接受用户的输入处理,可以是搜索关键字或者是网站,即搜索引擎or请求站点,所以ui线程第一步区分你是收索关键字还是请求站点,如果是url,那么会对url进行解析,比如协议,端口等
接下来ui线程会通知网络线程,发起网络请求(请求过程见ps2),第一步dns查找ip(可以展开讲 比如dns缓存机制和原理 见ps1),然后和服务器建立连接,如果是https的话还要协商一下多建立一个tls安全连接,我们有时候也可能会收到301状态码,那么我们网络的线程发起新的请求,我们要访问真正的地址。发起请求前会设置一些UA等头部的信息,然后发起请求,服务器拿到请求后找到对应应用里面处理的函数返回对应的资源即response返回给浏览器,浏览器读取response时候会分析response的数据类型,虽然head中会告诉数据类型 但是浏览器还是会做,因为告诉他的不一定是真的 浏览器会自己判断,接下来再解析这个response。浏览器还会做安全检查,判断你访问的域名是不是安全的,以及跨站攻击比如scprit标签的src里面有危险行为,然后告诉ui线程全部数据准备就绪
渲染线程:renderer process 最主要的线程是main process.浏览器以上几步完成后会告诉渲染线程一切ok,这时候其实就跳转到这个页面,有个新的tab,浏览器的历史标签会记录之前的页面.然后可以开始加载和渲染。
主线程接受html数据,解析dom构建dom树,同时引入外部的js/css资源,去加载这些资源。其实会做预扫描,看哪些外部子资源要加载(图片),然后一起并行加载和解析。当我们解析碰到scprit的时候,我们会暂停html解析,然后去执行js代码之后才会继续解析html,因为js可能会修改dom,所以会暂停解析。解决方法是:如果我们的js代码没用处理document.write,我们可以给script加上async或者defer关键字,表示并行加载或延迟 不阻塞dom解析。解析出dom树之后,我们要解析css计算出computed styles,构建布局树即大小和位置。
然后接下来是raster thread 和compositor thread 两个线程的事情,他会遍历布局树,决定绘制的顺序,将页面拆分成图层,,构建图层树,然后复合线程把图层复合为一个页面。
defer和async区别
2.首屏加载优化
1.什么是首屏加载?怎么优化?
什么是首屏加载:我们最先看到的是首页的一部分,我们要把最重要的一部分先显示出来。因为web增量加载的特定决定我们只能看到首页一部分一部分加载,因为我们所有的资源都要去服务端获取,资源又需要解析加载,所以肯定是一部分一部分出来。导致问题1.过长时间白屏 2.内容显示不完整
首屏用户最关键的三个时刻:1.第一个东西出来的时候 2.第一个有意义的东西出来的时候3.用户能不能用 即可以交互,对应一下三个性能指标
解决办法:
1.资源体积过大:资源本身压缩(比如图片在线压缩 html压缩),传输过程用gzip压缩,代码拆分,tree-shaking,(这两个都是减少文件本身体积),http2(多路复用),缓存机制(这两个都是传输上的)
2.首页内容太多:路由懒加载,先加载用到的组件;图片懒加载;ssr或者预渲染(提前生成html,不用到时候解析),首屏需要哪些html/css/js 我们把这些内嵌到Html文件中不用去请求,后续需要的文件让他后续懒加载
3.加载顺序不合适:prefetch,preload调整浏览器默认加载的文件的优先级
3.js内存管理
js会自动创建和释放内存但是只对几种基本类型 GC机制-即垃圾回收机制
所有GC都是近似实现的,即通过判断变量是否还能访问到,通过作用域来判断。
局部变量:函数执行完,没有闭包引用,就会被回收
全局变量:直到浏览器卸载页面才释放
GC实现机制:
1.引用计数:即我们创建变量后,我们看一下哪些人引用啦他,有一个则加1,但那些人被回收啦计数就减一,到0的时候这个变量就能回收 。但无法解决循环引用问题,比如a对象用了b对象 b对象用啦a对象 那么永远都有被引用 计数至少为1,他们两都没回收
2.标记清除:,mark and sweep 每隔一定时间从根节点去扫描 看看哪些节点访问不到做标记 访问不到就清除
问题:一直访问b元素 所以object不会被清除 a属性其实应该被清除的
代码解决
1.避免全局变量的产生:非严格模式下 没用let和用this 声明的变量会变成全局变量
2.避免反复运行形成闭包
返回的匿名函数会持有outer的上下文 比如有largeData,prevStore,inner等变量,然后下次运行又被保存到store里面一直保存下去最后就炸了
总之返回的如果是函数,这个函数就会保存上下文,因为他需要使用对应的变量,这样一直保存下去就会炸了
3.避免脱离的dom元素
detachedDiv其实还在内存中,你只是再dom树上消除啦 但是这个对象没消除
4.ps部分
1.dns解析:
1.输出一个Url,浏览器对其解析,取出域名
2.浏览器查找自身的dns缓存 查到返回对应ip
3.在本机host文件中找对应的ip,有则返回ip
4.没有的话,从本地的dns服务器开始查找,向各级的dns服务器发送查询报文
在每次查找的过程中,浏览器,应用程序,DNS服务器都会对域名进行缓存,如果命中缓存,DNS会直接返回对应的IP,没有命中则继续查找相关的域名服务器,定位IP
这部分能优化的做法 1.html增加dns缓存标签 2.域名解析到多个ip,实现dns的负载均衡
<link rel="dns-prefetch" href="//g.alicdn.com" />//提前解析之后可能会用到的域名,使解析结果缓存到系统缓存中,缩短DNS解析时间,来提高网站的访问速度。
2.http请求过程:
1.如果是第一次请求,dns解析拿到ip
2.客户端发送http报文给对应服务器,这个过程要经过应用层,传输层,网络层,数据链路层,物理层对这个报文处理(见ps3)
3.客户端和服务端进行三次握手建立tcp连接
4.服务端返回response给客户端
5.如果是两次以上的请求,浏览器或者服务器会通过http的header参数,判断资源是否过期,没用过期则用缓存,否则去服务器拿新的资源(见ps4)
3.各层对数据报的处理
1.应用层有很多协议比如http,ftp,pop3,浏览器会在应用层,把请求的数据报封装为按照http协议要求的格式,定义一系列请求的head字段,等待运输层接收。
2.运输层主要协议有tcp,udp,运输层拿到数据报之后,会先看是否和目的主机有连接,没有则进行三次握手,建立tcp连接,如果连接成功,会对数据报进一步封装,加上源主机端口号和目的主机端口号,然后给到网络层
3.网络层主要协议有ip协议,接受运输层的数据报,增加目的主机ip,封装成符合ip协议的ip数据报,然后给数据链路层
4.数据链路层有ARP协议,通过ip地址解析为为目的地址的mac地址,通过物理层转发出去,到达目的的局域网后,通过广播被目的主机接收
4.浏览器缓存策略
浏览器先看强缓存再看协商缓存
步骤:
1.当我们输入url,浏览器会去查看自身是否有缓存,如果没有缓存会直接请求服务器获取资源,并缓存到浏览器一份
2.如果浏览器有缓存,此时检查http的请求头,看cache-control、expires字段,判断是否过了缓存的有效期,如果没有过有效期,则返回200状态码和对应的缓存数据。
3、如果浏览器缓存已过期,就携带请求头字段If-None-Match和If-Modified-Since去服务器拉取资源,服务器看到这两个字段,发现和当前服务器资源一致,就直接返回缓存和状态码304。服务器一般会先验证If-None-Match/ETag,如果不变,再去验证If-Modified-Since/Last-Modified
即强制缓存是在浏览器端来判断的缓存,协商缓存是服务器来判断的缓存
1.强缓存
主要看http头的两个字段 expires , cache-control
expires是http1.0的定义,返回一个绝对的时间GMT,为过期时间。这就导致如果服务器时间和浏览器时间不一致,可能会使缓存失效。
cache-control是http1.1的定义,可以定义的值有
max-age=600 表示最长有效期为600s
no-cache 不走浏览器缓存,每次都去浏览器协商缓存
no-store 每次都请求服务器最新的资源(即也不判断浏览器缓存 也不走协商缓存 直接拿新资源)
private 私有,只能在用户终端缓存,不能在cdn或中间的服务器或者代理服务器缓存
public 公有,可以在所有节点缓存
两者同时存在则cache-control优先级高
2.协商缓存
看If-Modified-Since就是之前返回的Last-Modified,If-None-Match就是之前返回的ETag
5.cdn节点
客户端到服务器之间可能存在代理服务器或者cdn节点,相当于增加了一个缓存节点,cdn会判断是否过期,然后返回新资源
CDN的存在解决了跨地域请求的时延问题;对服务器压力进行了分流。
四次挥手:如果请求结束,服务器和客户端进行四次握手,断开连接。
6.dns解析
递归查询:都是由本地dns服务器去发出请求,顺序由根->顶级->二级 最终返回一个结果给客户端
迭代查询 客户端自己一个一个去请求 根->顶级->二级服务器 有多个返回结果给客户端
7.如何设置缓存
通过node设置header 或者ngnix设置
res.setHeader('max-age': '3600 public') //强制缓存
res.setHeader(etag: '5c20abbd-e2e8') //协商缓存
res.setHeader('last-modified': Mon, 24 Dec 2018 09:49:49 GMT)
ngnix:设置全部都要最新
8.三次握手和四次挥手
1.三次握手:
<1> 第一次握手
Client将标志位SYN置为1,随机产生一个值seq=x,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
<2> 第二次握手
Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=x+1,随机产生一个值seq=y,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
<3> 第三次握手
Client收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=y+1,并将该数据包发送给Server,Server检查ack是否为y+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
补充1:ack=x+1是指之前的x报文段我都收到了,ACK=1是指确定收到(acknowledgement 确认) syn=1是指请求发起连接 一边发一个请求发起连接即可,只用建立一个连接
补充2:SYN攻击
在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态(这个ACK=1表示客户端收到服务端发送的SYN-ACK)。SYN攻击就是Client在短时间内伪造大量不存在的源IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击是一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,使用如下命令可以让之现行:netstat -nap | grep SYN_RECV
补充3:为什么不能两次握手
1.TCP的三次握手过程:主机A向B发送连接请求;主机B对收到的主机A的报文段进行确认;主机A再次对主机B的确认进行确认。
2.采用三次握手是为了防止失效的连接请求报文段突然又传送到主机B,因而产生错误。失效的连接请求报文段是指:主机A发出的连接请求没有收到主机B的确认,于是经过一段时间后,主机A又重新向主机B发送连接请求,且建立成功,顺序完成数据传输后然后关闭连接。考虑这样一种特殊情况,主机A第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟达到主机B,主机B以为是主机A又发起的新连接,于是主机B同意连接,并向主机A发回确认,但是此时主机A根本不会理会,主机B就一直在等待主机A发送数据,导致主机B的资源浪费。如果只有两次握手,那么B就以为成功建立啦连接,然后等待,如果是三次,那么B此时只是半连接状态,没收到A的第三次的确认就知道关闭
2.四次挥手
<1> 第一次挥手
Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
<2> 第二次挥手
Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
<3> 第三次挥手
Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
<4> 第四次挥手
Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四
补充:
1. 为什么连接的时候是三次握手,关闭的时候却是四次挥手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。(即因为服务端还有数据没发送完,所以不能和ACK=1一起发送FIN=1)(FIN=1即发起关闭连接)
2. 为什么TIME_WAIT状态需要经过2MSL(maximum Segment Lifetime)(最大报文段生存时间)才能返回到CLOSE状态?
答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。(即可能客户端发送给服务端的最后一个ACK=1即确定收到服务端关闭的报文丢失,如果不重发这个报文,那么服务端就会一直等待浪费资源)
10.http和https
一、HTTP和HTTPS的基本概念
HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
二、HTTP与HTTPS有什么区别?
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。
HTTPS和HTTP的区别主要如下:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
三、HTTPS的缺点
虽然说HTTPS有很大的优势,但其相对来说,还是存在不足之处的:
(1)HTTPS协议握手阶段比较费时,会使页面的加载时间延长近50%,增加10%到20%的耗电;
(2)HTTPS连接缓存不如HTTP高效,会增加数据开销和功耗,甚至已有的安全措施也会因此而受到影响;
(3)SSL证书需要钱,功能越强大的证书费用越高,个人网站、小网站没有必要一般不会用。
(4)SSL证书通常需要绑定IP,不能在同一IP上绑定多个域名,IPv4资源不可能支撑这个消耗。
(5)HTTPS协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用。最关键的,SSL证书的信用链体系并不安全,特别是在某些国家可以控制CA根证书的情况下,中间人攻击一样可行。
**注意ps部分的1-5部分转载自:**juejin.cn/post/696881…