浏览器的核心包括两部分:
- 渲染引擎(也称为浏览器“内核”)(不同浏览器有不同的渲染引擎)
- 渲染网页代码
- 页面生成以后,脚本操作和样式表操作,都会触发“重流”和“重绘”
- JS 引擎(又称 JS 解释器)
- 读取网页中的 JS 代码,对其处理后运行
- JS 是一种解释型语言,也就是说,它不需要编译,由解释器实时运行。运行速度慢于编译型语言。
- 为了提高运行速度,目前的浏览器都将JS进行一定程度的编译,生成类似字节码的中间代码,以提高运行速读
- 字节码不能直接运行,而是运行在一个虚拟机(Viryual Machine)上,一般也把虚拟机称为 JS 引擎(如V8引擎)
两者都是单线程运行。单线程的优势是开发方便,避免多线程下的死锁、竞争等问题,劣势是失去了并发能力。
浏览器为了避免两个引擎同时修改页面而造成渲染结果不一致的情况,增加了另外一个机制:这两个引擎具有互斥性,也就是说在某个时刻只有一个引擎在运行,另一个引擎会被阻塞(可以简单理解为两个引擎共用一个线程)。
操作系统在进行线程切换的时候需要保存上一个线程执行时的状态信息并读取下一个线程的状态信息,俗称上下文切换。而这个操作相对而言是比较耗时的。
每次 DOM 操作就会引发线程的上下文切换——从 JavaScript 引擎切换到渲染引擎执行对应操作,然后再切换回 JavaScript 引擎继续执行,这就带来了性能损耗。单次切换消耗的时间是非常少的,但是如果频繁地大量切换,那么就会产生性能问题。
另一个更加耗时的因素是元素及样式变化引起的再次渲染,在渲染过程中最耗时的两个步骤为回流(Reflow)与重绘(Repaint)。
这两个因素导致了我们常说的DOM操作慢
浏览器架构
通过浏览器的任务管理器(快捷键 Shift + ESC),我们可以看到,当打开一个标签页的时候,启动了下面几个进程:
![284261a6908d92a5467f74fde0163dec.png](https://i-blog.csdnimg.cn/blog_migrate/0e4e476bc20bd0cd06a4de3c6d62d661.png)
浏览器进程
负责界面展示(地址栏、导航栏、书签等)、处理用户事件、管理子进程
GPU 进程
处理来自其他进程的 GPU 任务,比如来自渲染进程或扩展程序进程的 CSS3 动画效果,来自浏览器进程的界面绘制等。
Network Service 进程
负责页面的网络资源加载,比如在地址栏输入一个网页地址,网络进程会将请求后得到的资源交给渲染进程处理。本来只是浏览器主进程的一个模块,现在为了将浏览器进程进行“服务化”,被抽取出来,成了一个单独的进程。
渲染进程
浏览器会为每个标签页单独启动一个渲染进程,所以它和上述进程不同,并不是唯一的。
渲染进程的任务是将 HTML、CSS 和 JavaScript 转化为⽤户可以与之交互的网页,每个渲染进程都会启动单独的渲染引擎线程和 JavaScript 引擎线程。
扩展程序进程
主要是负责插件的运⾏,和渲染进程一样,也不是唯一的,浏览器会为每个插件都启动一个进程。这样的设计也是从安全性和稳定性考虑。
浏览器环境
Javascript 是浏览器内置脚本语言。即浏览器内置了 JavaScript 引擎,并提供各种接口,供 JS 调用。
网页中嵌入 JS 代码,主要有四种方式:
- 1.<script>元素直接嵌入代码。
- 2.<script>标签加载外部脚本。
- 3.事件属性:<button id="myBtn" οnclick="console.log(this.id)">点击</button>
- 4.URL 协议:URL 支持 javascript: 协议,即在 URL 的位置写入代码,使用这个 URL 的时候就会执行 JavaScript 代码。(<a href="javascript:console.log('Hello')">点击</a>)
window 对象
浏览器中,window 对象指当前的浏览器浏览器窗口,它也是当前页面的顶层对象,其他所有对象都是它的下属。