进程和线程:
进程是一个工厂,工厂之间相互独立
线程是工厂中的工人,多个工人(线程)协作完成任务
工厂内有一个或多个工人-工人之间共享空间
工厂的资源->系统分配的内存(独立的一块内存)
工厂之间相互独立->进程之间相互独立
多个工人协作完成任务->多个线程在进程中协作完成任务
工厂内有一个或多个工人->一个进程由一个或多个线程组成
工人之间共享空间->同一进程下的各个线程之间共享程序的内存空间
进程是cpu资源分配的最小单位(系统会给它分配内存)
单线程和多线程,都是指在一个进程内的单和多
浏览器是多进程
浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu,内存)
每打开一个tab页,就相当于创建了一个独立的浏览器进程
注意:打开多个tab页时,浏览器可能合并进程
浏览器包含进程:
Browser进程:浏览器的主进程,只有一个。作用:
负责浏览器界面显示,与用户交互。如前进后退
负责各个页面的管理,创建和销毁其他进程,包括地址栏,书签栏,前进后退等
将Renderer进程得到的内存中的Bitmap绘制到用户界面上
网络资源的管理,下载等
第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
GPU进程:最多一个,用于3D绘制等
浏览器渲染进程(浏览器内核)(Renderer进程,内部是多线程的):默认每个tab页一个进程,互不影响。主要作用:
页面渲染,脚本执行,事件处理等
在浏览器中打开一个网页相当于新起了一个进程(进程内有自己的多线程)
普通前端操作渲染进程(render进程)
主要常驻线程:
GUI渲染线程:
渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。
重绘页面会引发回流时
注意:GUI渲染线程与JS引擎线程是互斥的,GUI更新会被保存在一个队列中等到JS引擎空闲时执行
JS引擎线程:
处理JavaScript脚本(如V8引擎)
解析JavaScript脚本,运行代码。
一个tab页中无论什么时候都只有一个JS线程在运行JS程序,所以时间都是排队等JS线程处理
事件触发线程:
归属于浏览器,用来控制事件循环
执行setTimeOut、鼠标点击、ajax请求等时,会将对应任务添加到事件线程中,等待JS引擎处理
定时触发器线程:
setInterval和setTimeOut所在的线程,计时完毕后添加到事件队列中,
setInterval精确地隔一段时间推入一个事件(但是,事件的实际执行时间不一定就准确,还有可能是这个事件还没执行完毕,下一个事件就来了)
多个setInterval的代码执行时间可能会比预期小(因为代码执行需要时间)
目前最佳方案是由setTimeOut模拟setInterval,或者直接用requestAnimationFrame
异步http请求线程:
在XMLHttpRequest在连接后通过浏览器新开一个线程请求
检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调放入事件队列中,等待JS引擎线程执行
Browser进程和浏览器内核(Renderer进程)的通信过程
Browser进程收到用户请求--获取页面内容--通过Renderer接口传递给Render进程
Renderer进程的Renderer接口收到消息--解释--交给渲染线程--开始渲染
渲染线程接收请求--加载并渲染网页(可能需要Browser进程获取资源和需要GPU进程帮助渲染)
JS线程操作DOM(回流、重绘)
Render进程将结果传递给Browser进程
Browser进程接收结果并绘制
浏览器内核中线程之间的关系
GUI渲染线程与JS引擎线程互斥
当JS引擎执行时GUI线程会被挂起,GUI更新则会被保存在一个队列中等到JS引擎线程空闲时立即被执行
JS阻塞页面加载
尽量避免JS执行时间过长,否则页面渲染会不连贯,会有页面渲染加载阻塞的感觉。
WebWorker(属于render进程下的一个线程)
针对cpu密集型计算,创建Worker时,JS引擎向浏览器申请开一个子线程(子线程是浏览器开的,完全受主线控制,而且不能操作DOM),并不意味着JS语言本身支持了多线程的能力,而是浏览器作为宿主环境提供了JS一个多线程运行的环境。
JS引擎线程与worker线程间通过特定的方式通信(postMessage API,需要通过序列化对象来与线程交互特定的数据)
ps:
把对象转换为字节序列的过程称为对象的序列化
把字节序列恢复为对象的过程称为对象的反序列化。
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。
注意点:
- 同源限制且非本地(加载的脚本必须来自网络)
- 无法读取主线程所在网页的DOM对象,也不能获取document、window等对象,但是可以获取navigator、location(只读)、XMLHttpRequest、setTimeout等浏览器API
- worker线程不能执行alert、confirm,但可以使用XMLHttpRequest对象发出ajax请求
SharedWorker(由独立的进程管理)
浏览器所所有页面共享,被多个Render进程共享
Chrome浏览器为SharedWorker单独创建一个进程来运行JavaScript程序,在浏览器中每个相同的JavaScript只存在一个SharedWorker进程,不管它被创建多少次。
浏览器渲染流程
浏览器输入url,浏览器主进程(Browser进程)接管,开一个下载线程,然后进行http请求
浏览器渲染流程
- 解析html建立dom树
- 解析css构建render树(将css代码解析成树形的数据结构,然后结合DOM合并成render树)
- 布局render树(Layout/reflow),负责各元素尺寸、位置的计算
- 绘制render树(paint),绘制页面像素信息
- 浏览器会将各层的信息发送给GPU,GPU会将各层合成,显示在屏幕上。
渲染完毕--load事件--JS逻辑处理
WebKit主流程:
Moziolla的Gecko呈现引擎主流程:
load事件与DOMContentLoaded事件的先后
DOMContentLoad触发时:仅当DOM加载完成,不包括样式表,图片。$(document).ready(function() { // ...代码... });
onload事件触发时:页面上所有的DOM,样式表,脚本,图片都已经加载完成。$(document).load(function() { // ...代码... });
CSS加载
css由单独的下载线程异步下载
css加载不会阻塞DOM树解析,但会阻塞render树渲染(渲染时需等css加载完毕,因为render树需要css信息)