
浏览器是多进程多线程的,js是单线程的
二、浏览器进程 Browser进程(主进程) 负责浏览器界面显示,与用户交互。如前进,后退等负责各个页面的管理,创建和销毁其他进程将Renderer进程得到的内存中的Bitmap,绘制到用户界面上网络资源的管理,下载等 第三方插件进程 每种类型的插件对应一个进程,仅当使用该插件时才创建 GPU进程 最多一个,用于3D绘制,硬件加速 浏览器渲染进程-(浏览器内核)(Renderer进程,内部是多线程的):默认每个Tab页面一个进程,互不影响。主要作用为页面渲染,脚本执行,事件处理等
三、浏览器线程 GUI渲染线程 负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。当界面需要重绘(Repaint)或由于某种 *** 作引发回流(reflow)时,该线程就会执行注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。 JS引擎线程 也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)JS引擎线程负责解析Javascript脚本,运行代码。JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序同样注意,GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。 事件触发线程 归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理注意,由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行) 定时触发器线程 传说中的setInterval与setTimeout所在线程浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)注意,W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms。 异步http请求线程 在XMLHttpRequest在连接后是通过浏览器新开一个线程请求将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。再由JavaScript引擎执行。 四、常见问题 浏览器渲染过程 输入地址,browser进程获取请求,然后通过网络请求获取页面内容获取到页面内容后browser通过RenderHost的接口传递到Render进程Render进程将获取的内容简单解析后交给渲染线程开始渲染最后会browser进程会将render进程返回结果绘制在用户界面上 3中渲染线程做了啥 解析html生成DOM树解析css生成CSSOM树DOM和CSSOM生成渲染树(渲染树只会显示需要显示的节点和节点信息,如果某个节点是display: none则不会显示)生成布局(也叫回流),即将所有渲染树的所有节点进行平面合成(明确每个节点的位置和大小)将布局绘制(paint)到屏幕上(布局完成后浏览器会立即发出“Paint setup“ 和 ”Paint”事件)
构建DOM
浏览器会遵守一套步骤将HTML 文件转换为 DOM 树。宏观上,可以分为几个步骤:
,生成节点对象并构建成DOM
渲染过程中遇到js怎么处理
JavaScript的加载、解析与执行会阻塞DOM的构建。如果引入了JavaScript,CSSOM会阻塞DOM的构建(但不会阻塞DOM的解析),原本DOM和CSSOM的构建是互不影响的,但是因为js不仅会
进行dom的 *** 作,还会对样式进行修改,而不完整的CSSOM是无法使用的,所以当js遇到 *** 作CSS的时候,js会阻塞等待CSSOM的构建完成,而js又阻塞了DOM的构建,所以CSSOM变相的阻塞了DOM的构建
回流必定会发生重绘,重绘不一定会引发回流
元素布局、尺寸、隐藏等改变会发生回流
元素外观、风格等不影响布局的改变会发生重绘
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
其中蓝色线代表JavaScript加载;红色线代表JavaScript执行;绿色线代表 HTML 解析。
因为DOM是渲染引擎的东西,而js是js引擎的东西,我们 *** 作DOM的时候必然会涉及两个线程之间的通信,会带来一些性能的损耗,而且 *** 作dom还可能会带来回流重绘的情况,也回影响性能
优化渲染效率的建议 样式文件应当在 head 标签中,而脚本文件在 body 结束前,这样可以防止阻塞的方式。简化并优化CSS选择器,尽量将嵌套层减少到最小。尽量减少在 JavaScript 中进行DOM *** 作修改元素样式时,更改其class属性是性能最高的方法尽量用 transform 来做形变和位移 强缓存和协商缓存判断是什么缓存是通过去看response header的cache-control得出的,cache-control的值不同表示不同的缓存策略
cache-control: max-age=xxxx,public客户端和代理服务器都可以缓存该资源;客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,如果用户做了刷新 *** 作,就向服务器发起http请求cache-control: max-age=xxxx,private
只让客户端可以缓存该资源;代理服务器不缓存。客户端在xxx秒内直接读取缓存,statu code:200cache-control: max-age=xxxx,immutable
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,即使用户做了刷新 *** 作,也不向服务器发起http请求cache-control: no-cache
跳过设置强缓存,但是不妨碍设置协商缓存;一般如果你做了强缓存,只有在强缓存失效了才走协商缓存的,设置了no-cache就不会走强缓存了,每次请求都回询问服务端。cache-control: no-store
不缓存,这个会让客户端、服务器都不缓存,也就没有所谓的强缓存、协商缓存了。
协商缓存的标识是在response header设置
etag: '5c20abbd-e2e8'
last-modified: Mon, 24 Dec 2018 09:49:49 GMT
etag:是一个hash,每个文件都有一个,文件改变hash就变了
last-modified:文件修改时间,精确到秒
也就是说,每次请求返回来 response header 中的 etag和 last-modified,在下次请求时在 request header 就把这两个带上,服务端把你带过来的标识进行对比,然后判断资源是否更改了,如果更改就直接返回新的资源,和更新对应的response header的标识etag、last-modified。如果资源没有变,那就不变etag、last-modified,这时候对客户端来说,每次请求都是要进行协商缓存了
协商缓存步骤总结:
请求资源时,把用户本地该资源的 etag 同时带到服务端,服务端和最新资源做对比。
如果资源没更改,返回304,浏览器读取本地缓存。
如果资源有更改,返回200,返回最新的资源。
js是单线程的,我们的js代码分为同步和异步代码
所有代码在js主线程中按顺序执行,当遇到了异步代码(一些可能会耗时的 *** 作),
会将这些异步任务放到其他线程执行(事件触发线程、定时触发器线程、异步http请求线程),
当这些异步任务执行有了结果就会在事件队列存入一个事件,
当主线程中的同步代码执行完之后就会读取事件队列的结果到主线程执行
js异步有一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入事件队列,然后在执行微任务,将微任务放入事件队列;
需要注意的是,这两个事件队列不是一个队列。当你往外拿的时候先从微任务里拿这个回掉函数,然后再从宏任务的队列上拿宏任务的回掉函数
其中宏任务有:整体代码script,setTimeout,setInterval
微任务有:Promise,process.nextTick
浏览器原理
深入浅出浏览器渲染原理
彻底弄懂强缓存和协商缓存
javascript的宏任务和微任务
js中的同步和异步的个人理解
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)