浏览器是多进程的
1、进程简单的理解就是,进程里边有很多线程,例如进程是QQ,
线程就是会话聊天;
2、浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu
,内存);
3、简单的理解,没打开一个tab页就相当于创建一个独立的浏览器进程;
1.浏览器里边的进程
1.1、Brower
进程:
浏览器的主进程(负责协调、主控),只有一个;
作用:
a、负责浏览器界面显示,与用户交互,如前进后退等;
b、负责各个页面的管理,创建和销毁其他进程;
c、将Renderer
进程得到的内存中的Bitmap
,绘制到用户界面上;
d、网络资源的管理,下载等;
1.2、第三方插件进程
每种类型的插件对应一个进程,仅当使用该插件时才创建;
1.3、GPU进程
最多一个,用于3D
绘制等;
1.4、渲染进程(浏览器内核)(Renderer
进程,内部是多线程的)
a、默认每个Tab页面是一个进程,互不影响;
b、主要作用为页面渲染,脚本执行,事件处理等;
2.渲染进程是多线程
2.1、GUI渲染线程
1、负责渲染浏览器界面,解析HTML
,CSS
,构建DOM
树和RenderObject
树,布局和绘制等;
2、当界面需要重绘(Repaint)或流于某种操作引起的回流(reflow
)时,该线程就会执行;
3、GUI
渲染线程与js
引擎线程是互斥的,当js引擎执行时,GUI
线程会被挂起(相当于冻结),GUI
更新会被保存在一个队列中等到js
引擎空闲时立即被执行;
2.2、js引擎线程
1、被称为js
内核,负责处理js脚本程序(例如V8
引擎);
2、js
引擎线程负责解析js
脚本,运行代码;
3、js
引擎一直等待任务队列中任务的到来,然后加以处理,一个Tab
页(Renderer
进程)中只有一个js线程在运行;
4、GUI
线程和js
引擎线程是互斥的,如果js
执行时间过长,要放在body
下,否则会导致页面渲染加载阻塞;
2.3、事件触发线程
1、管理事件队列;
2、监听事件,符合条件时把回调函数放入事件队列中;
2.4、定时触发器线程
1、setInterval
与setTimeout
在此线程中计时完毕后,把回调函数放入事件队列中;
2、浏览器定时计数器并不是由js
引擎计数的(由于js
引擎是单线程的,如果处于阻塞线程状态就会影响计时准确),所以通过单独线程来计时并触发(计时完毕后,添加到事件队列中,等待js
引擎空闲后执行)
3、w3c
在html
标准中规定,规定要求setTimeout
中抵御4ms
的时间间隔算为4ms
;
2.5、异步http请求线程
1、检测到XHR对象状态变化时,将回调函数放入事件队列中;
2、将检测到状态变更时,如果设置有回调函数,异步线程就会产生状态变更事件,将这个回调在放入时间队列,再由js引擎执行;
2.6、渲染引擎与js引擎互斥
由于js是可执行操作DOM的,如果在修改这些元素属性同时渲染界面(js线程和UI线程同时运行),那么渲染线程前后获得的元素数据就可能不一致;
所以为了防止渲染出现不可预期的结果,浏览器设置GUI渲染线程与js引擎为互斥关系,当js引擎执行时GUI线程会被挂起,GUI更新则会保存在一个队列中等到js引擎线程空闲时立即被执行;
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script>
// 页面上的hello world不会变成红色
document.getElementById("app").style.color = "red";
</script>
</head>
<body>
<div id="app">
hello world!
</div>
</body>
</html>
// js阻塞页面加载
/* 由于上边所说的互斥关系,可以推论出,js如果执行时间过长就会阻塞页面,加入js引擎正在进行巨量计算,此时就算GUI有更新,也会被保存在队列中,等待js引擎空闲后执行;由于巨量计算,所以要等待很久后才能空闲,页面就会很卡很卡
尽量避免js执行时间过长,否则会造成页面渲染不连贯,导致页面渲染加载阻塞的感觉*/
总结: css加载不会阻塞DOM树解析(异步加载时DOM照常构建),但会阻塞render树渲染(渲染时需要等css加载完毕,因为render树需要css信息)
js会阻塞DOM解析