图解 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 执行逻辑

图解 Google V8 # 18 :异步编程:V8是如何实现微任务的?

图解 Google V8 # 13:字节码:V8为什么又重新引入字节码?