进程
CPU资源分配的基本单位,系统分配的独立资源,由一个或多个线程组成
线程
CPU调度和分派的基本单位,进程的执行流,同个进程中多个线程之间是共享该进程的资源的。
浏览器内核
浏览器是多进程的,浏览器的每个tab标签都代表一个独立进程(多个空白tab标签会合并成一个进程),浏览器内核(浏览器渲染进程)属于浏览器多进程中的一种。
线程种类:
GUI渲染线程:
- 负责渲染页面,解析HTML,css构成的dom树等,当页面重绘或者由于某种操作引起回流都会调起该线程。
- 和js引擎线程是互斥的,当js引擎线程在工作时,GUI渲染线程会被挂起,GUI更新被放入在js任务队列中,等待js引擎线程空闲的时候继续执行。
Js引擎线程:
- 单线程,负责解析运行js脚本。
- 和GUI渲染线程互斥,js运行耗时过长会导致页面阻塞。
事件触发线程:
- 符合条件被触发时,将对应的事件回调函数添加到任务队列的队尾,等待js引擎处理。
定时器触发线程:
- 不是由js引擎计数,阻塞会导致计时不准。
- 开启定时器触发线程来计时并触发计时,计时完成会添加到任务队列中,等js引擎处理。
HTTP请求线程:
- HTTP请求的时候开启,有结果之后,将请求的回调函数添加到任务队列中,等js引擎处理。
js是单线程
每次只能执行一项任务,其他任务都要排队,当前任务执行完才能执行下一个任务。
1、所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
2、主线程之外,还存在一个任务队列(task queue)。只要异步任务有了运行结果,就在任务队列中放置一个事件。
3、一旦主线程的栈中的所有同步任务执行完毕,系统就会读取任务队列,选择需要首要执行的任务然后执行。
事件循环机制
调用栈中的同步任务都执行完毕,栈被清空,就代表主线程空闲,然后去任务队列中按顺序读取一个任务放到栈中执行。每次栈内被清空,都会读取任务队列有没有任务,有就读取执行,循环读取执行的操作形成了事件循环。
事件任务
任务队列是先进先出的数据结构
执行顺序:同步任务 => 微任务 => 宏任务 => 异步任务
宏任务(macro-task):定时器、事件绑定、ajax、回调函数
微任务(micro-task):promise(then和catch是异步,其他同步,相当于promise对象是同步)
Async(/əˈsɪŋk/):同步,相当于promise对象
Await:异步,相当于then
同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
异步任务:不进入主线程、而进入”任务队列”的任务,当主线程中的任务运行完了,才会从”任务队列”取出异步任务放入主线程执行
浏览器渲染机制
**关键渲染路径:**浏览器从最初接收的HTML、css、js等资源,然后解析构建树、渲染布局、绘制,最后呈现给用户能看到的界面的过程。
耗时的主要任务:
1、DNS解析查询
2、TCP/IP连接(三握手四挥手)
三次握手建立连接
- 请求发起方向服务方发起请求
- 服务方听到请求返回ack
- 请求发起方收到这个请求也回一个ack
为什么是三次?
因为三次最少,如同打电话。少三次不能保证可靠。多一次没必要
四次挥手断开连接
- 客户端发起请求给服务端。
- 服务端收到请求,对这个请求回一个ack。
- 服务端处理完和客服端相关的剩余数据,向客户端发起请求,告诉他断联。
- 客户端收到这个请求返回ack,服务端收到请求断联。
3、http请求和响应
http协议
超文本传输协议,一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。
请求方式:
1XX:信息 100 101
2XX:成功 200 201
3XX:重定向
4XX:客户端错误 404
5XX:服务器错误 502
get和post区别
GET 和 POST 报文上的区别?
有实质区别,只是报文格式不同(原因:HTTP协议是基于TCP/IP的应用层协议,无论GET还是POST,用的都是同一个传输层协议,所以在传输上,没有区别。)
Git方法参数固定吗?
不固定一般写在?后边&分割也有,user/name/chengqm/age/22
Get、post安全比拼?
从请求报文角度,get比post安全
从传输角度都不安全,因为http网络是明文传输的,只要在网络节点捉包,就能完整获取报文想要安全只有加密https
Git长度限制原因?
http协议对body和url没限制,对url限制大都是浏览器和服务器的原因
服务器处理长的url主要是要消耗较多资源,为了性能和安全才限制
Post方法会产生两个TCP数据包?
没有明确说会产生连个tcp数据包,实际测试发现header和body不会分开发送。
Header和body分开是部分浏览器或框架的请求方法,不属于post必然行为。
4、服务器响应
5、客户端渲染
- 解析html生成dom树
- 解析css生成cssom规则树
- 将dom树与cssom规则树合并在一起生成渲染树
- 遍历渲染树开始布局,计算每个节点的位置大小信息
- 将渲染树每个节点绘制到屏幕
注:以上步骤不是一次完成的,如果dom和cssom被修改,以上过程需要重复执行,这样才能计算需要重复执行,这样才能计算出那些像素需要在屏幕上进行重新渲染。
阻塞渲染
遇到script标记阻塞时,解析器虽然会停止构建DOM,但仍会执行JavaScript脚本的资源直至脚本执行完再开始构建DOM;如果JavaScript脚本还操作了CSS,而正好这个CSSOM还没有下载和构建,这时就存在阻塞的资源,浏览器会延迟JavaScript脚本执行直至完成其CSSOM的下载和构建再执行。
遵循两个原则
CSS优先:引入顺序上,CSS资源先于JavaScript资源JavaScript置后:我们通常把JS代码放到页面底部,且JavaScript应尽量少影响DOM的构建
js下载完成后,渲染引擎中断渲染,执行这个脚本以后,再继续渲染,这个过程中多个脚本按下载完成的时间的先后顺序依次执行
使用媒体类型(media type)和媒体查询(media query)
<link href="vue.css" rel="stylesheet" media="print">
//设置了媒体类型,会加载但不会阻塞
<link href="vue.css" rel="stylesheet" media="(min-width: 30em) and (orientation: landscape)">
//提供了媒体查询,会在符合条件时阻塞渲染
<script src="vue.js" defer></script> defer的script将会并发异步的去下载对应的外部脚本文件(可能从本地缓存中获取)js下载完成后不会马上执行,// 要等到HTML解析完成后,按脚本出现的顺序依次执行,这个过程中多个脚本之间是顺序执行(即延迟执行引入的js脚本)<script src="vue.js" async></script>// async的script将会并发异步的去下载对应的外部脚本文件(可能从本地缓存中获取)
构建渲染树
Render Tree的构建其实就是DOM Tree和CSSOM Attach的过程(每个DOM节点都有一个“attach”方法)
样式计算:
样式计算是个很复杂的问题。DOM中的每个节点可以对应样式表中的多个元素,样式表包括了所有样式:浏览器默认样式表,定义样式表,inline样式元素,HTML可视化属性如:width=100
注:display等于none的不会被显示在渲染树里,但是visibility等于hidden的元素是会显示在渲染树里的
渲染树布局
创建渲染树后,下一步就是布局(Layout),或者叫回流(reflow),这个过程就是通过渲染树中渲染对象的信息,计算出每一个渲染对象的位置和尺寸,将其安置在浏览器窗口的正确位置,而有些时候我们会在文档布局完成后对DOM进行修改,这时候可能需要重新进行布局,也可称其为回流,本质上还是一个布局的过程,每一个渲染对象都有一个布局或者回流方法,实现其布局或回流。
渲染树绘制
在绘制阶段,系统会遍历渲染树,并调用渲染器的“paint”方法,将渲染器的内容显示在屏幕上。绘制工作是使用用户界面基础组件完成的。
垃圾回收机制
原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。
(1)标记清除法
声明一个变量的时候,就将这个变量标记为“进入环境”。
从逻辑上讲,永远都不能释放进入环境的变量作占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
垃圾回收器在运行时候会给存储在内存中中的所有变量都加上标记。然后它会去掉环境中的变量以及被环境中的变量引用的变量的标记(闭包)。在此之后再被标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾回收器完成内存清楚工作,销毁那些带标记的值并回收他们所占用的内存空间
(2)引用计数法
跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当圾回收器下次再运行时,它就会释放那些引用次数为0的值所占用的内存。
但是很重要的一点是当遇到循环引用的时候,函数的引用次数就不会为0,所以不会被垃圾回收器回收内存,会造成内存泄露。在IE中涉及COM对象,就会存在循环引用的问题。
浏览器缓存
浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档。
强缓存与协商缓存的共同点是:如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;没有命中的时候,浏览器直接从服务器加载资源数据。
区别
1、强缓存不发请求到服务器,协商缓存会发请求到服务器,通过服务器告知缓存是否可用。
2、强缓存状态码200,协商缓存状态码304
304:如果客户端发送了一个带条件的git请求,且该请求已经被允许,而文档的内容(自上次访问以来或根据请求的条件)并没有改变,则服务器应当返回304
强缓存
Header实现:Expires和Cache-Control
浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上Expires的header
浏览器在接收到这个资源后,会把这个资源连同所有response header一起缓存下来(所以缓存命中的请求返回的header并不是来自服务器,而是来自之前缓存的header);
浏览器再请求这个资源时,先从缓存中寻找,找到这个资源后,拿出它的Expires跟当前的请求时间比较,如果请求时间在Expires指定的时间之前,就能命中缓存,否则就不行。
如果缓存没有命中,浏览器直接从服务器加载资源时,Expires Header在重新加载的时候会被更新。
设置
1、cache-control: max-age=xxxx,public
客户端和代理服务器都可以缓存该资源;
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200,如果用户做了刷新操作,就向服务器发起http请求
2、cache-control: max-age=xxxx,private
只让客户端可以缓存该资源;代理服务器不缓存
客户端在xxx秒内直接读取缓存,statu code:200
3、cache-control: max-age=xxxx,immutable
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200,即使用户做了刷新操作,也不向服务器发起http请求
4、cache-control: no-cache
跳过设置强缓存,但是不妨碍设置协商缓存;一般如果你做了强缓存,只有在强缓存失效了走协商缓存的,设置了no-cache就不会走强缓存了,每次请求都回询问服务端。
5、cache-control: no-store
不缓存,这个会让客户端、服务器都不缓存,也就没有所谓的强缓存、协商缓存了
协商缓存
Header实现:Last-Modified和ETag
浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在
respone的header加上Last-Modified的header,这个header表示这个资源在服务器上的最后修改时间
浏览器再次跟服务器请求这个资源时,在request的header上加上If-Modified-Since的header,这个header的值就是上一次请求时返回的Last-Modified的值
浏览器收到304的响应后,就会从缓存中加载资源