V8是如何执行JavaScript代码的?
前言
一般来讲,电脑是不能直接运行我们的javascript代码的,它需要一个翻译程序将人类能够理解的编程语言 JavaScript,翻译成机器能够理解的机器语言。目前市面上有很多种 JavaScript 引擎,诸如 SpiderMonkey、V8、JavaScriptCore 等。而由谷歌开发的开源项目 V8 是当下使用最广泛的 JavaScript 虚拟机,全球有超过 25 亿台安卓设备,而这些设备中都使用了 Chrome 浏览器,所以我们写的 JavaScript 应用,大都跑在 V8 上。
如果这篇文章有帮助到你,️关注+点赞️鼓励一下作者,文章公众号首发,关注 前端南玖 第一时间获取最新文章~
什么是V8
在 V8 出现之前,所有的 JavaScript 虚拟机所采用的都是解释执行的方式,这是 JavaScript 执行速度过慢的一个主要原因。而 V8 率先引入了即时编译(JIT)的双轮驱动的设计,这是一种权衡策略,混合编译执行和解释执行这两种手段,给 JavaScript 的执行速度带来了极大的提升。通俗点理解就是:V8是一个高性能的JavaScript解析执行引擎
对与很多开发者来说,V8就像是一个黑盒,我们将一段代码丢给这个黑盒,它便会返回结果,我们只知道V8 的主要职责是用来编译执行 JavaScript 代码的,并没有深入了解过它的工作原理。
下面我们就来深入了解一下V8到底是如何执行JavaScript代码的。
为什么需要编译这一过程?
我们先从 CPU 是怎么执行机器代码讲起,你可以把 CPU 看成是一个非常小的运算机器,我们可以通过二进制的指令和 CPU 进行沟通,比如我们给 CPU 发出“1000100111011000”的二进制指令,这条指令的意思是将一个寄存器中的数据移动到另外一个寄存器中,当处理器执行到这条指令的时候,便会按照指令的意思去实现相关的操作。为了能够完成复杂的任务,工程师们为 CPU 提供了一大堆指令,来实现各种功能,我们就把这一大堆指令称为指令集(Instructions),也就是机器语言。
CPU 能直接识别汇编语言吗?
显然是不行的,如果你使用汇编编写了一段程序,你还需要一个汇编编译器,其作用是将汇编代码编程成机器代码
计算机执行高级语言的基本方式
一般来讲,计算机执行高级语言的方式有以下两种:
解释执行
改方式需要先将输入的源代码通过解析器编译成中间代码,之后直接使用解释器解释执行中间代码,然后直接输出结果。
编译执行
采用这种方式时,也需要先将源代码转换为中间代码,然后我们的编译器再将中间代码编译成机器代码。通常编译成的机器代码是以二进制文件形式存储的,需要执行这段程序的时候直接执行二进制文件就可以了。还可以使用虚拟机将编译后的机器代码保存在内存中,然后直接执行内存中的二进制代码。
即便是JavaScript一门语言,也有好几种流行的虚拟机,它们之间的实现方式也存在着部分差异,比如Chrome使用的是V8虚拟机,Safari使用的是JavaScript Core虚拟机,而Firefox则使用的是TraceMonkey虚拟机。
V8是如何执行JavaScript代码的?
作为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和作用域生成字节码
- 解释执行字节码
- 监听热点代码
- 优化热点代码为二进制的机器代码
- 优化生成二进制机器代码
V8是如何执行JavaScript代码的?的更多相关文章
- C#执行javascript代码
最近在做网站自动登陆小工具,遇到技术屏障.密码在submit时会使用js进行加密.这时我需要模拟这个加密过程,想到使用C#执行javascript代码. 对于执行javascript代码,纯代码方式使 ...
- python中执行javascript代码
python中执行javascript代码: 1.安装相应的库,我使用的是PyV8 2.import PyV8 ctxt = PyV8.JSContext() ctxt.enter() ...
- JAVA中执行JavaScript代码并获取返回值
JAVA中执行JavaScript代码并获取返回值 场景描述 实现思路 技术要点 代码实现 测试方法 运行结果 改进空间 场景描述 今天在CSDN上偶然看到一个帖子对于一段字符串 “var p=‘xx ...
- Java执行JavaScript代码
Java执行JavaScript代码 这篇文章主要为大家详细介绍了Java执行JavaScript代码的具体操作方法,感兴趣的小伙伴们可以参考一下 我们要在Java中执行JavaScriptMetho ...
- UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等)
UWP 中使用 WebView 时可以在网页中额外执行一些代码.于是你几乎可以在网页上做任何事情,那些你可以在浏览器控制台中做的事情. 本文将介绍做法. 本文内容 准备环境 执行 JavaScript ...
- UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) - walterlv
原文:UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) - walterlv UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) ...
- 尚学堂 215 在java中执行JavaScript代码
package com.bjsxt.test; import java.io.FileReader; import java.net.URL; import java.util.List; impor ...
- 转:selenium webdriver 执行javascript代码
在用selenium webdriver 编写web页面的自动化测试代码时,可能需要执行一些javascript代码,selenium本身就支持执行js,我们在代码中import org.openqa ...
- 如何正确的加载和执行 JavaScript 代码
无论当前 JavaScript 代码是内嵌还是在外链文件中,页面的下载和渲染都必须停下来等待脚本执行完成.JavaScript 执行过程耗时越久,浏览器等待响应用户输入的时间就越长.浏览器在下载和执行 ...
- selenium webdriver ——执行javascript代码
在代码中import org.openqa.selenium.JavascriptExecutor;就可以使用executeScript.executeAsyncScript这两个方法了 execut ...
随机推荐
- Wondershare Recovery - 万兴数据恢复专家,恢复你 Mac 上的重要文件
Wondershare Recoverit 是恢复被删除文件最有效的软件之一.计算机用户面临的一个主要问题是失去机密信息.我们可能是误删除了数据和文件,或者可能是由于病毒袭击.操作系统故障或硬盘故障而 ...
- offsetX与offsetLeft
offsetX:鼠标指针距离当前绑定元素左侧距离,他并不是相对于带有定位的父盒子的x,y坐标, 记住了,很多博客都解释错了 offsetLeft,offsetTop 相对于最近的祖先定位元素.
- ACM-NEFU15届校赛-大二组
A.小林找工作 #include<bits/stdc++.h> using namespace std; const int MAXN=1e5+10; int p[MAXN]; int m ...
- 基于Label studio实现UIE信息抽取智能标注方案,提升标注效率!
基于Label studio实现UIE信息抽取智能标注方案,提升标注效率! 项目链接见文末 人工标注的缺点主要有以下几点: 产能低:人工标注需要大量的人力物力投入,且标注速度慢,产能低,无法满足大规模 ...
- stm32的学习笔记1
一 目录结构管理 Libraries是放官方固件库的 MDK-ARM是放产生的文件的,工程存放的目录 USERS是放自己写的代码的 然后是一个解释文件README 在MDK-ARM目录里还要创建两个文 ...
- pandas之窗口函数
为了能更好地处理数值型数据,Pandas 提供了几种窗口函数,比如移动函数(rolling).扩展函数(expanding)和指数加权函数(ewm).窗口函数应用场景非常多.举一个简单的例子:现在有 ...
- [Java]Maven构建时报错: "Error:java: 读取E:\XX\XXX..jar时出错; error in opening zip file"
删除本地仓库中对应的jar包,pom.xml再reimport
- 《Flask Web 开发指南 pt.2》
哈喽大家好,我是咸鱼 在<Flask Web 开发指南 pt.1>中,咸鱼跟大家介绍了 Flask 的由来--诞生于一个愚人节玩笑,简单介绍了一些关于 Flask 的概念,并且编写了一个简 ...
- this关键字,static以及子类访问父类super关键字
1.this是用来指代当前类实例化对象 public setid(id){thiis.id = id;} 即将传入的形参id赋值给当前类的id属性 2.this还可以调用方法,方法分为两种构造方法和普 ...
- 数据泵:impdp导入用户ORA-01653
,问题描述:在导入一个用户数据的时候,大小为14G左右,导进来的时候卡半天,后来发现是表空间满了,已经恢复了大概6G左右,剩下8G左右没有恢复.此时磁盘剩余19G,加了15G的表空间,磁盘就剩下4G左 ...