写在前面
浏览器可以算是最常用的一类软件了,但是对于它你又了解多少呢?通过本系列文章,可以对浏览器的工作原理有一个基本的了解。
浏览器架构
架构演进
- 单进程架构:所有模块运行在同一个进程里,包含网络、插件、JS 运行环境等。
- 多进程架构:主进程、网络进程、渲染进程、GPU 进程、插件进程。
- 面向服务架构:将原来的 UI、数据库、文件、设备、网络等,作为一个独立的基础服务。
渲染进程
多线程架构
内部是多线程实现,主要负责页面渲染、脚本执行、事件处理、网络请求等。
JS 引擎 & 渲染引擎
- 解析执行 JS
- XML 解析生成渲染树,显示在屏幕
- 桥接方式通信
JS 引擎是指 JavaScript 解释器,它负责解析并执行 JavaScript 代码。而渲染引擎则是负责将 HTML、CSS 和 JavaScript 代码转换为可视化的内容,例如网页。
在浏览器中,JS 引擎和渲染引擎通常是分别由不同的组件实现的。因此,JS 引擎和渲染引擎之间的桥接通信就非常重要了。这种通信的主要作用是将 JavaScript 代码中涉及到 DOM、样式表等页面元素的修改操作传递给渲染引擎,从而更新网页的显示。
在现代浏览器中,JS 引擎和渲染引擎之间的桥接通信通常是通过一些中间层实现的。例如,Chrome 浏览器中的 V8 JS 引擎和 Blink 渲染引擎之间就有一个称为 “WebCore” 的中间层,它负责处理 JS 引擎和渲染引擎之间的通信,并将页面元素的修改操作传递给渲染引擎。
多线程工作流程
-
网络线程负责加载网页资源。
-
JS 引擎解析 JS 脚本并且执行。
-
JS 解析引擎空闲时,渲染线程立即工作。
在浏览器中,JS 引擎和渲染引擎是通过事件循环来协作工作的。事件循环是一个循环,它会不断地从事件队列中获取事件并执行相应的回调函数,直到队列为空。而事件队列中的事件可以来自各种来源,例如用户输入、定时器、网络请求等。
在这个事件循环中,JS 引擎和渲染引擎都会有自己的任务要执行。当 JS 引擎执行完自己的任务后,如果事件队列中没有其他优先级更高的任务需要执行,那么它就会将控制权交给渲染引擎,让它继续处理页面的显示工作。这样做的好处是可以避免阻塞渲染引擎,保证页面的流畅显示。
虽然在这个过程中,JS 引擎的优先级确实比渲染引擎高,但这并不意味着页面的显示不重要。毕竟,没有良好的用户体验,网站就无法吸引用户,也难以持续发展。因此,在浏览器中,JS 引擎和渲染引擎之间的协作是非常重要的,它们需要平衡各自的任务,以确保页面的显示和交互都能得到良好的体验。
-
用户交互、定时器操作等产生回调函数放入任务队列中。
-
事件线程进行事件循环,将队列里的任务取出,交给 JS 引擎执行。
事件循环(Event Loop)是指浏览器或 Node.js 等异步编程环境中处理事件的机制。它是一种循环结构,用于不断地从事件队列中获取事件并执行相应的回调函数,直到队列为空。
事件循环的基本原理是先将所有同步任务依次执行完毕,然后再从事件队列中选择最早的任务(也称为“宏任务”),执行它的回调函数,直到该任务执行完毕。如果在执行宏任务的过程中,产生了微任务(Microtask),那么这些微任务会被优先执行,直到所有微任务都被执行完毕。然后再从事件队列中选择最早的宏任务,继续执行。
需要注意的是,在执行宏任务和微任务的过程中,可能会产生新的宏任务和微任务,它们会被放入事件队列中等待执行。因此,事件循环是一个不断重复的过程,它会持续不断地处理事件,直到事件队列为空。