浏览器的进程模型:
1.浏览器进程
主要负责界面显示、用户交互、子进程管理等。
2.网络进程
负责加载网络资源。内部会分为多个进程处理不同的网络任务。
3.渲染进程
启动后,开启一个渲染主线程,负责执行html,css,js文件。
默认情况下,浏览器为每一个标签页开启一个新的渲染进程,以保证不同标签之前互不影响。(chrome)
【未来有可能是一个站点一个进程】
渲染主进程的任务:
- 解析HTML
- 解析CSS
- 计算样式
- 布局
- 处理图层
- 每秒把页面画60次 (FPS)
- 执行全局JS代码
- 执行事件处理函数
- 执行计时器的回调函数
- …
如何调度这么多任务呢?
- 渲染主进程开启一个无限循环
- 每次循环检查消息队列是否不为空。不为空,则取出第一个任务执行;为空,则进入休眠状态
- 其他所有线程可以随时向消息队列中添加任务。新任务会加到消息队列的末尾,在添加新任务时,如果主线程时休眠状态,则会将其唤醒并继续循环拿取任务
补充了解:
什么是异步?
即 无法立即处理的任务
- 计时完成后需要执行的任务 —— setTimeout, setInterval
- 网络通信完成后需要执行的任务 —— XHR,fetch
- 用户操作后需要执行的任务 —— addEventListener
这种任务来临之后,如果让渲染主线程等待任务完成,主线程会长期处于阻塞的状态,这样连基本的页面刷新都会卡住。
此时,需要用异步执行方式代替同步,如图
计时线程开始计时后,渲染主进程即进行MQ中的下一个任务。而等计时结束后,会往MQ中添加新的任务,等待主线程执行。
这种异步模式下,浏览器不会阻塞,保证了单线程的流畅。
提问:
为某一按钮绑定事件如下,为何点击后效果是先卡住页面3秒,再变化文字?
btn.onclick = function(){
h1.textContent = "HELLO";
delay(3000);
}
function delay(n){
const pre = Date.now();
while(Date.now()-pre<n){}
}
dom的文本更换,导致添加一个绘制任务。此任务排在MQ中等待执行,而3000ms的死循环已经开始在执行了
这个案例说明,JS会阻碍渲染。因为你执行JS,那么渲染就要滞后;你正在执行渲染,JS就要等着。
任务有优先级吗
任务本身没有优先级,在消息队列中先进先出
- 每个任务都有一个任务类型,同一个类型的任务必须在一个队列,不同类型的任务可以在一个队列。
- 浏览器必须准备好一个微队列,微队列中的任务优先与其他所有任务的执行。
目前Chrome实现中包括但不限于这些队列,队列有对应的优先级
- 延时队列:用于存放计时器到达后的回调任务,优先级 中
- 交互队列:用于存放用户操作后产生的事件处理任务,优先级 高
- 微队列:需要最快执行的任务,优先级最高
微队列中接收的主要是Promise 、MutationObserver
如图这样的队列结构,渲染主线程结束当前任务后,依次往下找优先级最高的任务载入执行,比如微队列执行完清空了再往下找最高的任务,所以有时候优先级高的会后来居上。
可以用来分析许多的面试题。