V8是如何执行JavaScript代码的?

数字游侠说
• 阅读 3914

前言

一般来讲,电脑是不能直接运行我们的javascript代码的,它需要一个翻译程序将人类能够理解的编程语言 JavaScript,翻译成机器能够理解的机器语言。目前市面上有很多种 JavaScript 引擎,诸如 SpiderMonkey、V8、JavaScriptCore 等。而由谷歌开发的开源项目 V8 是当下使用最广泛的 JavaScript 虚拟机,全球有超过 25 亿台安卓设备,而这些设备中都使用了 Chrome 浏览器,所以我们写的 JavaScript 应用,大都跑在 V8 上。

如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,文章公众号首发,关注 前端南玖 第一时间获取最新文章~

什么是V8

在 V8 出现之前,所有的 JavaScript 虚拟机所采用的都是解释执行的方式,这是 JavaScript 执行速度过慢的一个主要原因。而 V8 率先引入了即时编译(JIT)的双轮驱动的设计,这是一种权衡策略,混合编译执行和解释执行这两种手段,给 JavaScript 的执行速度带来了极大的提升。通俗点理解就是:V8是一个高性能的JavaScript解析执行引擎

V8是如何执行JavaScript代码的?

对与很多开发者来说,V8就像是一个黑盒,我们将一段代码丢给这个黑盒,它便会返回结果,我们只知道V8 的主要职责是用来编译执行 JavaScript 代码的,并没有深入了解过它的工作原理。

下面我们就来深入了解一下V8到底是如何执行JavaScript代码的。

为什么需要编译这一过程?

我们先从 CPU 是怎么执行机器代码讲起,你可以把 CPU 看成是一个非常小的运算机器,我们可以通过二进制的指令和 CPU 进行沟通,比如我们给 CPU 发出“1000100111011000”的二进制指令,这条指令的意思是将一个寄存器中的数据移动到另外一个寄存器中,当处理器执行到这条指令的时候,便会按照指令的意思去实现相关的操作。为了能够完成复杂的任务,工程师们为 CPU 提供了一大堆指令,来实现各种功能,我们就把这一大堆指令称为指令集(Instructions),也就是机器语言。

CPU 能直接识别汇编语言吗?

显然是不行的,如果你使用汇编编写了一段程序,你还需要一个汇编编译器,其作用是将汇编代码编程成机器代码

计算机执行高级语言的基本方式

一般来讲,计算机执行高级语言的方式有以下两种:

解释执行

改方式需要先将输入的源代码通过解析器编译成中间代码,之后直接使用解释器解释执行中间代码,然后直接输出结果。

V8是如何执行JavaScript代码的?

编译执行

采用这种方式时,也需要先将源代码转换为中间代码,然后我们的编译器再将中间代码编译成机器代码。通常编译成的机器代码是以二进制文件形式存储的,需要执行这段程序的时候直接执行二进制文件就可以了。还可以使用虚拟机将编译后的机器代码保存在内存中,然后直接执行内存中的二进制代码。

V8是如何执行JavaScript代码的?

即便是JavaScript一门语言,也有好几种流行的虚拟机,它们之间的实现方式也存在着部分差异,比如Chrome使用的是V8虚拟机,Safari使用的是JavaScript Core虚拟机,而Firefox则使用的是TraceMonkey虚拟机。

V8是如何执行JavaScript代码的?

作为JavaScript的主流虚拟机,V8是如何编译执行JavaScript代码的呢?它采用的是我们上面介绍的解释执行、编译执行中的哪一种呢?

解释执行的启动速度快,但是执行速度比较慢,而编译执行的启动速度慢,但是执行速度比较快,所以为了权衡两种方法各自的优缺点,V8采用的是两种方法结合的方式进行编译执行JavaScript代码。

V8执行JavaScript代码流程图

V8是如何执行JavaScript代码的?

  • 从这张图的左侧部分我们可以看出,V8在启动执行JavaScript代码之前,它需要初始化好执行环境,这些环境包括:堆空间栈空间全局执行上下文全局作用域循环系统♻️内置函数等,这些内容都是在JavaScript执行过程中需要使用到的。

<!---->

  • 在初始化完执行环境后,就可以向V8提交需要执行的JavaScript代码了。

<!---->

  • V8在接收到JavaScript代码后,并不会立即执行,因为V8并不能直接理解JavaScript代码的含义,这对于它来说只不过就是一段字符串而已。它需要将代码结构化生成抽象语法树(AST),在生成抽象语法树的同时,V8还会生成相应的作用域。
  • 有了AST和作用域后,就可以生成字节码了,字节码是介于AST和机器代码之间的中间代码。
  • 生成字节码后,解释器就会按照顺序解释执行字节码,并输出执行结果。
  • 解释器在执行字节码的过程中,如果发现某段代码被多次重复执行,那么这段代码就会被标记成热点代码。
  • 当某段代码被标记成热点代码后,V8就会将这段代码交给优化编辑器,优化编辑器会在后台将字节码编译为二进制代码,然后再对编译后的二进制代码进行优化操作,优化后的二进制机器代码的执行效率就会大幅提升。

总结

由于计算机只能识别二进制指令,所以一般需要将高级代码编译成计算机能够识别的二进制指令才能执行,一般有两种方法:编译执行和解释执行。

两种方法各有优缺点,所以V8采用了一种权衡策略,在启动时采用解释执行的策略,但是如果某段代码的执行频率超过某个值,V8就会采用优化编译器将其编译成执行效率更高的机器代码。

V8执行JavaScript代码的主要流程:

  • 初始化执行环境
  • 解析JavaScript代码生成AST和作用域
  • 根据AST和作用域生成字节码
  • 解释执行字节码
  • 监听热点代码
  • 优化热点代码为二进制的机器代码
  • 优化生成二进制机器代码
点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Karen110 Karen110
4年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
SpiderMonkey安装
SpiderMonkey是Mozilla使用C/C开发的JavaScript引擎,该引擎已经在多个产品中使用。是用SpiderMonkey我们能够在命令行中调试和开发JavaScript代码。下载SpiderMonkey:https://developer.mozilla.org/enUS/docs/Mozilla/Projects/
Stella981 Stella981
3年前
JavaScript 执行效率不行?因为你还没用 V8
作为当下使用最广泛的JavaScript引擎,V8的生态圈非常庞大,这与它革命性的设计密不可分。V8出现之前,所有JavaScript引擎用的都是解释执行的方式,这是JS执行速度过慢的主要原因;而V8引入的即时编译(JIT)双轮驱动设计,混合编译执行和解释执行两种手段,为JavaScript的执行速度带来了极大
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Node.js 安装与开发
Node.js简介Node.js是一个Javascript运行环境(runtime),发布于2009年5月,由RyanDahl开发,实质是对ChromeV8引擎进行了封装。Node.js对一些特殊用例进行优化,提供替代的API,使得V8在非浏览器环境下运行得更好。V8引擎执行Javascript的速度非常快,性能非常好。Node.j