进程与线程之间的关系
进程是CPU资源分配的最小单位,是能拥有资源和独立运行的最小单位。(系统会给他分配内存)
线程是CPU调度的最小单位。(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)
浏览器是多进程的。浏览器之所以能够运行,是因为系统给他的进程分配了资源。
css什么情况下会阻塞dom树的渲染
如果页面中同时存在css和js,并且js在css后面,两个都放在head中,则DOMContentLoaded事件会在css加载完后才执行。
JS是单线程的,加载时间过长会阻塞页面的渲染,造成卡顿,因为JS引擎线程和GUI渲染线程是互斥的,JS引擎线程工作时,GUI线程会被挂起。
因此,可以用WebWorker在后台线程中运行脚本,它运行在另一个全局上下文中,不同于当前的window,因此,使用 window快捷方式获取当前全局的范围 (而不是self) 在一个 Worker 内将返回错误。JS引擎线程和webworker线程通过postMessage API进行通信,所以有非常耗时的工作,可以交给webworker线程。这并不影响JS引擎是单线程的,因为webworker是浏览器新开的线程,相当于给JS引擎开的额外挂。
WebWorker 和 SharedWorker的区别
- WebWorker只属于某一个页面,不会和其他页面的Renderer进程共享。一个页面就是一个Renderer进程。
- SharedWorker是浏览器所有页面共享的,可以为多个Renderer进程共享使用。Chrome浏览器为SharedWorker单独创建一个进程来运行JavaScript程序,在浏览器中每个相同的JavaScript只存在一个SharedWorker进程,不管它被创建多少次。
- 本质上就是进程和线程的区别。SharedWorker由独立的进程管理,WebWorker只是属于render进程下的一个线程。
浏览器的多进程
1.Browser进程(浏览器的主进程)
2.第三方插件进程
3.GPU进程(最多一个)
4.浏览器渲染进程(浏览器的内核),内部多线程,主要负责页面渲染,脚本执行,事件处理。在浏览器中打开一个网页,相当于新建了一个进程。
浏览器多进程的优点
- 避免单个page crash影响整个浏览器
- 避免第三方插件crash影响整个浏览器
- 多进程充分利用多核优势
- 方便使用沙盒模型隔离插件等进程,提高浏览器稳定性
Renderer进程(浏览器内核)
对前端来说,最重要的进程是渲染进程。在这个进程中会进行页面的渲染,JS的执行,事件的循环。 主要包括:
- GUI渲染线程:负责渲染浏览器界面,解析HTML,CSS,构建DOM树,布局树,生成绘制列表。回流和重绘也会触发该线程的执行。注意,GUI渲染线程与JS引擎线程是互斥的, 当JS引擎线程执行时,GUI线程会被挂起,GUI更新会被保存在一个队列中,直到JS引擎线程更新时才会被执行。
- JS引擎线程:主要处理JS脚本程序,比如V8引擎。一个渲染进程中无论什么时候都只有一个JS线程在运行JS程序。同样,GUI渲染线程与JS引擎线程是互斥的。
- 事件触发线程:归属于浏览器而不是JS引擎,用来控制事件循环。当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。
- 定时触发器线程:浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的,如果处于阻塞线程状态就会影响记计时的准确)。注意,W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms。
- 异步http请求线程:在XMLHttpRequest连接后是通过浏览器新开一个线程请求。将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。再由JavaScript引擎执行。

浏览器进程与Renderer进程的通信
- Browser进程收到用户请求,首先需要获取页面内容(譬如通过网络下载资源),随后将该任务通过RendererHost接口传递给Render进程。
- Renderer进程的Renderer接口收到消息,简单解释后,交给渲染线程,然后开始渲染。渲染线程接收请求,加载网页并渲染网页,这其中可能需要Browser进程获取资源和需要GPU进程来帮助渲染。当然可能会有JS线程操作DOM(这样可能会造成回流并重绘)。最后Render进程将结果传递给Browser进程。
- Browser进程接收到结果并将结果绘制出来。
DOMContentLoaded与load的先后顺序
DOMContentLoaded:仅当DOM加载完成,不包括样式。
load:渲染完成。
DOMContentLoaded->load。
普通图层与复合图层
浏览器渲染的图层一般分为普通图层和复合图层。普通文档流内可以理解为一个复合图层(这里称为默认复合层,里面不管添加多少元素,其实都是在同一个复合图层中)。absolute布局(fixed也一样),虽然可以脱离普通文档流,但它仍然属于默认复合层。然后,可以通过硬件加速的方式,声明一个新的复合图层,它会单独分配资源 (当然也会脱离普通文档流,这样一来,不管这个复合图层中怎么变化,也不会影响默认复合层里的回流重绘)。GPU中,各个复合图层是单独绘制的,所以互不影响, 这也是为什么某些场景硬件加速效果一级棒。
如何变成复合图层,进行硬件加速?
- translate3d, translateZ
<video><iframe><canvas><webgl>等元素opacity属性/过渡动画(需要动画执行的过程中才会创建合成层,动画没有开始或结束后元素还会回到之前的状态)。
复合图层的作用
采用硬件加速,不占用主线程资源,避免重流和重绘。
absolute和硬件加速的区别?
absolute虽然可以脱离普通文档流,但无法脱离默认复合层。所以,就算absolute中信息改变时不会改变普通文档流中render树, 但是,浏览器最终绘制时,是整个复合层绘制的,所以absolute中信息的改变,仍然会影响整个复合层的绘制。 (浏览器会重绘它,如果复合层中内容多,absolute带来的绘制信息变化过大,资源消耗是非常严重的)。而硬件加速直接就是在另一个复合层了(另起炉灶),所以它的信息改变不会影响默认复合层 (当然了,内部肯定会影响属于自己的复合层),仅仅是引发最后的合成(输出视图)。
硬件加速时要使用z-index,避免层爆炸问题。
具体的原理是这样的: webkit CSS3中,如果这个元素添加了硬件加速,并且index层级比较低, 那么在这个元素的后面其它元素(层级比这个元素高的,或者相同的,并且releative或absolute属性相同的), 会默认变为复合层渲染,如果处理不当会极大的影响性能。
事件循环时,一个宏任务执行结束后,先执行微任务,然后渲染页面,再进行下一个宏任务。
宏任务是由事件触发线程维护的,微任务是由JS引擎线程维护的。
DNS解析过程
-
- 首先系统会检查浏览器本地缓存有没有这个域名对应的解析过的IP地址。
-
- 如果用户的浏览器缓存中没有,就去检查操作系统缓存即本地的Host文件。
-
- 如果本地Host文件中没有,操作系统就把域名发送给本地域名服务系统即Local DNS。
-
- 如果仍然没有命中,就发给Root Server域名服务器请求解析。
-
- Root Server会返回给本地域名服务器一个所查找的域的gTLD主域名服务器地址。
-
- 本地服务器再向所返回的这个gTLD服务器发送请求。
-
- 接受请求的gTLD服务器查找并返回此域名对应的Name Server域名服务器的地址。
-
- Name Server域名服务器会查找域名与IP地址的关系映射表,连同一个TTL值返回给DNS Server。
-
- Local DNS会缓存所返回的该域名的IP和TTL值,缓存时间由TTL控制。
-
- 把解析的结果返回给用户。用户根据TTL值缓存在本地系统缓存中。
CDN原理
-
- 当用户点击网站页面上的内容URL,经过本地DNS系统解析,DNS系统会最终将域名的解析权交给CNAME指向的CDN专用DNS服务器。
-
- CDN的DNS服务器将CDN的全局负载均衡设备IP地址返回用户。
-
- 用户向CDN的全局负载均衡设备发起内容URL访问请求。
-
- CDN全局负载均衡设备根据用户IP地址,以及用户请求的内容URL,选择一台用户所属区域的区域负载均衡设备,告诉用户向这台设备发起请求。
-
- 区域负载均衡设备会为用户选择一台合适的缓存服务器提供服务,选择的依据包括:根据用户IP地址,判断哪一台服务器距用户最近;根据用户所请求的URL中携带的内容名称,判断哪一台服务器上有用户所需内容;查询各个服务器当前的负载情况,判断哪一台服务器尚有服务能力。基于以上这些条件的综合分析之后,区域负载均衡设备会向全局负载均衡设备返回一台缓存服务器的IP地址。
-
- 全局负载均衡设备把服务器的IP地址返回给用户
-
- 用户向缓存服务器发起请求,缓存服务器响应用户请求,将用户所需内容传送到用户终端。如果这台缓存服务器上并没有用户想要的内容,而区域均衡设备依然将它分配给了用户,那么这台服务器就要向它的上一级缓存服务器请求内容,直至追溯到网站的源服务器将内容拉到本地。