一、认识浏览器内核
在生活中或者是工作中,我们对浏览器已经非常熟悉,比如谷歌浏览器、Microsoft浏览器、搜狗浏览器、360浏览器等,我们可以用它购物、阅读、聊天等等,但是浏览器是如何把网页渲染出来的呢?用户为何可以使用鼠标进行某些点击操作的呢?接下来,我们来了解浏览器的组成及其工作原理和渲染过程。
1.组成
- 不同的浏览器有不同的内核组成
- Gecko:早期被Netscape和Mozilla Firefox浏览器浏览器使用;
- Trident: 微软开发,被IE4~IE11浏览器使用,但是Edge浏览器已经转向Blink;
- Webkit:苹果基于KHTML开发、开源的,用于Safari,Google Chrome之前也在使用;
- Blink: 是Webkit的一个分支,Google开发,目前应用于Google Chrome、Edge、Opera等;
- 事实上,我们常说的浏览器内核指的是浏览器的排版引擎、
- 排版引擎,也称为浏览器引擎、页面渲染引擎或样板引擎。
2、浏览器的工作流程
当我们在浏览器中输入一个IP地址或者是一个网页链接时,那么浏览器是如何访问的服务器资源的呢?
3.浏览器渲染过程
浏览器在获取相关文件资源时,如何进行渲染的呢?
二、V8引擎
在开发中,我们大部分开发人员会使用谷歌浏览器,这是因为谷歌浏览器的V8引擎,在解析和运行JS代码时的速度和渲染效率是很高的。接下来我们来详细讲解V8引擎的工作原理。
1、认识V8引擎
V8是用C ++编写的Google开源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等。它实现ECMAScript和WebAssembly,并可在Windows 、macOS、Linux系统上运行。同时V8可以独立运行,也可以嵌入到任何C++应用程序中。
2、V8引擎的结构
(1)Parse模块会将JavaScript代码转换成AST。如果函数没有被调用,那么是不会被转换成AST的
(2)Ignition是一个解释器,会将AST转换成ByteCode。同时会收集TurboFan优化所需要的信息;如果函数只调用一次,Ignition会执行解释执行ByteCode。
(3)TurboFan是一个编译器,可以将字节码编译为CPU可以直接执行的机器码。如果一个函数被多次调用,那么就会被标记为热点函数,那么就会经过TurboFan转换成优化的机器码,提高代码的执行性能;同样机器码实际上也会被还原为ByteCode,如果后续执行函数的过程中,类型发生了变化,之前优化的机器码并不能正确的处理运算,就会逆向的转换成字节码。
(4)生成AST树后,会被Ignition转成字节码,之后的过程就是代码的执行过程。
三、V8引擎中执行JS代码过程
1.初始化全局对象、执行上下文栈(调用栈)
1.1 初始化全局对象
js引擎会在执行代码之前,会在堆内存中创建一个全局对象:GlobalObje(GO),特点:
(1)该对象的作用域为全局作用域;
(2)包含Date、Arra、String、Number、setTimeOut等;
(3)有一个window对象,指向自己,即:window = GO;
1.2执行上下文栈
js引擎内部有一个执行上下文栈(Execution Context Stack,简称ECS),它是用于执行代码的调用栈。
2.V8引擎中执行JS代码过程解析
JS引擎在执行代码前,创建了一个全局对象,同时会生成一个全局执行上下文Global Execution Context,简称:GEC,GEC会被放在调用栈中。那么此时在内存中,有以下结构,称为最初结构。
下面根据具体代码来详细说明每一步做了什么:
案例
var a = 10;
function foo() {
console.log(a);
}
foo();
-
代码解析阶段:
- JavaScript 引擎首先对代码进行词法分析和语法分析,识别出变量声明
var a
和函数声明function foo
。 - 在全局执行上下文中的变量对象中创建变量
a
和函数foo
的引用,但此时它们的值都为undefined。
- JavaScript 引擎首先对代码进行词法分析和语法分析,识别出变量声明
-
代码执行阶段:
- 遇到
var a = 10
,将值10
赋给变量a
在全局执行上下文中的变量对象中的引用。 - 当执行到
function foo() { console.log(a); }
时,创建函数foo
的执行上下文,并将其压入调用栈。在函数foo
的执行上下文中,会有自己的变量对象和作用域链,但由于函数内部没有声明变量a
,它会沿着作用域链向上查找,在全局执行上下文的变量对象中找到变量a
。 - 执行
foo()
,调用函数foo
,在函数内部执行console.log(a)
,打印出全局变量a
的值10
。
- 遇到
在整个过程中,JavaScript 引擎通过调用栈管理执行上下文的入栈和出栈操作,以确保代码按照正确的顺序执行。同时,作用域链使得变量和函数在不同的执行上下文中能够正确地被访问和引用。