Skip to content

代码运行过程

源代码- >解析器(parser)->AST->解释器(interperter)->字节码->编译器(TurboFan)->汇编 Pasted image 20250903153123.png

Parser生成抽象语法树

在Chrome中开始下载Javascript文件后,Parser就会开始并行在单独的线程上解析代码。这意味着解析可以在下载完成后仅几毫秒内完成,并生成ASTPasted image 20250903153157.png

AST的生成过程是怎么样的呢?

1. 词法分析(lexical analysis):主要是将字符流(char stream) 转换成标记流(token stream),字符流就是我们一行一行的代码,token是指语法上不能再分的、最小的单个字符或者字符串。

2. 语法分析:将前面生成的token流根据语法规则,形成一个有元素层级嵌套的语法规则树,这个树就是AST。在此过程中,如果源代码不符合语法规则,则会终止,并抛出“语法错误”。

Pasted image 20250903153451.png Ignition执行上一步生成的字节码,并记录代码运行的次数等信息,如果同一段代码执行了很多次,就会被标记为 “HotSpot”(热点代码),然后把这段代码发送给 编译器TurboFan,然后TurboFan把它编译为更高效的机器码储存起来,等到下次再执行到这段代码时,就会用现在的机器码替换原来的字节码进行执行,这样大大提升了代码的执行效率。
另外,当TurboFan判断一段代码不再为热点代码的时候,会执行去优化的过程,把优化的机器码丢掉,然后执行过程回到Ignition。

堆栈内存

栈内存ECS

计算机开辟的内存空间用于执行JS代码,也叫执行环境栈。代码在执行前会自身形成一个执行上下文,会进入栈中执行。执行完的代码可能会出栈

Pasted image 20250907202410.png 上述过程(简单数据类型)在内存中会:

  1. 创建一个值为10
  2. 创建一个变量x
  3. 将变量和值关联在一起

变量对象(VO)

专门用来存储创建的值和变量。

  • 如果内存中存在已经创建过的变量,便不会再创建,会直接进行关联。
  • 一个变量同一时间只能关联一个值,但一个值可以关联多个变量。

ECS(执行环境栈)

用于管理执行上下文的栈结构,代码执行时会形成执行上下文并压入栈中,执行完毕后可能出栈。

简单数据类型在内存中的处理

var x = 10为例:

  1. 首先进行声明动作(var x,也叫declare)。
  2. 然后进行定义/赋值动作(x = 10,也叫defined)。 在内存中会:
  3. 创建一个值为10
  4. 创建一个变量x
  5. 将变量和值关联在一起。 还有类似var y; console.log(y); // undefined的情况,变量y被声明但未赋值,所以打印undefined

引用数据类型在内存中的处理

创建引用数据类型分三步:

  1. 开辟一个==堆内存==,并自动生成一个16进制的地址。
  2. 将创建的复杂值(对象等)本身的属性放到堆中。
  3. 把这个16进制的地址交给变量(存在==栈==中)。 比如:
javascript
var x = {n: 10};
var y = x;
y.n = 20;
console.log(x.n); // 20

这里xy指向同一块堆内存地址,所以修改y的属性,x的属性也会改变。

函数声明在内存中的声明

  1. 函数是==引用==类型。
  2. 在堆中开辟空间后,其中存储函数相关内容,并以字符串的形式保存。
  3. 函数在创建时的执行上下文就被保存,内存中以[Scope](Scope.md)来存储其作用域等信息。
  4. 函数在执行时会形成全新的私有上下文并压入栈执行。

函数执行进栈后发生的事情

  1. 初始化自身的作用域链(包含上级上下文等,和全局执行上下文的查找机制类似)。
  2. 初始化this指向:在全局函数调用中,this指向window(浏览器环境下)。
  3. 初始化形参集合:arguments(类数组,存储函数调用时的实参等)。
  4. 形参赋值:将实参的值赋给对应的形参。
  5. 变量提升:只有通过var声明的变量或者函数声明才会提升。变量提升是指变量的声明会被提升到当前作用域的顶部,但赋值不会提升;函数声明整体会被提升。
  6. 代码执行:按顺序执行函数内的代码。
  7. 执行完之后出栈:函数执行完毕,其执行上下文从执行环境栈中弹出,释放相关资源(当然,若有引用指向堆中的内容,堆内容不会立即释放)。

执行上下文Execution Context

  • 全局执行上下文(GEC):window
  • 函数执行上下文:每个函数有特有的环境,函数可以访问外面的变量(闭包)
  • 块级执行上下文:在{}中的letconst无法在外面访问到,ES6提出