图解 Google V8 # 09:运行时环境:运行JavaScript代码的基石
Posted 凯小默
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图解 Google V8 # 09:运行时环境:运行JavaScript代码的基石相关的知识,希望对你有一定的参考价值。
说明
图解 Google V8 学习笔记
运行时环境
在执行 javascript 代码之前,V8 就已经准备好了代码的运行时环境,包括:
- 堆空间和栈空间
- 全局执行上下文
- 全局作用域
- 内置的内建函数
- 宿主环境提供的扩展函数和对象
- 消息循环系统
什么是宿主环境?
要执行 V8,则需要有一个宿主环境,宿主环境可以是浏览器中的渲染进程,可以是 Node.js 进程, 也可以是其他的定制开发的环境,而这些宿主则提供了很多 V8 执行 JavaScript 时所需的基础功能部件。
宿主环境和 V8 的关系:
V8 和浏览器的渲染进程的关系看成病毒和细胞的关系:
- 浏览器为 V8 提供基础的消息循环系统、全局变量、Web API
- V8 的核心是实现了 ECMAScript 标准,这相当于病毒自己的 DNA 或者 RNA,V8 只提供了 ECMAScript 定义的一些对象和一些核心的函数,这包括了 Object、Function、String。
- 除此之外,V8 还提供了垃圾回收器、协程等基础内容,不过这些功能依然需要宿主环境的配合才能完整执行。
构造数据存储空间:堆空间和栈空间
栈空间
栈空间主要是用来管理 JavaScript 函数调用的,栈是内存中连续的一块空间,同时栈结构是“先进后出”的策略。
特点:
- 先进后出
- 空间连续
- 查找效率非常高
函数调用过程中,什么会存在栈里:
- 原生类型
- 引用到的对象的地址
- 函数的执行状态
- this 值等
V8 对栈空间的大小做了限制,超出就会报栈溢出的错误:Uncaught RangeError: Maximum call stack size exceeded
。
例子:
堆空间
堆空间是一种树形的存储结构,用来存储对象类型的离散的数据,以及一些占用内存比较大的数据。
存在堆空间的:
- 函数
- 数组
- 在浏览器中还有 window 对象
- document 对象等
全局执行上下文和全局作用域
V8 初始化了基础的存储空间之后,接下来就需要初始化全局执行上下文和全局作用域。
当 V8 开始执行一段可执行代码时,会生成一个执行上下文来维护执行当前代码所需要的变量声明、this 指向等。
执行上下文中主要包含:
- 变量环境
- 词法环境:包含了使用 let、const 等变量的内容
- this 关键字
全局执行上下文在 V8 的生存周期内是不会被销毁的,它会一直保存在堆中。
例子:
var x = 5
let y = 2
const z = 3
这段代码在执行时,会有两个对应的作用域,一个是全局作用域,另外一个是括号内部的作用域,但是这些内容都会保存到全局执行上下文中。
构造事件循环系统
V8 还需要有一个主线程,用来执行 JavaScript 和执行垃圾回收等工作。
V8 是寄生在宿主环境中的,它并没有自己的主线程,而是使用宿主所提供的主线程,V8 所执行的代码都是在宿主的主线程上执行的。
在执行完代码之后,为了让线程继续运行,通常的做法是在代码中添加一个循环语句,在循环语句中监听下个事件。
如果主线程正在执行一个任务,这时候又来了一个新任务,那么这种情况下就需要引入一个消息队列,让新任务暂存到消息队列中,等当前的任务执行结束之后,再从消息队列中取出正在排队的任务。当执行完一个任务之后,我们的事件循环系统会重复这个过程,继续从消息队列中取出并执行下个任务。
事件循环系统主要用来处理任务的排队和任务的调度。
以上是关于图解 Google V8 # 09:运行时环境:运行JavaScript代码的基石的主要内容,如果未能解决你的问题,请参考以下文章
图解 Google V8 # 21 :垃圾回收:V8是如何优化垃圾回收器执行效率的?
图解 Google V8 # 17:消息队列:V8是怎么实现回调函数的?
图解 Google V8 # 01:V8 是如何执行一段 JavaScript 代码的?
图解Google V8,搞懂 JavaScript 执行逻辑