前言

一般来讲,电脑是不能直接运行我们的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代码的?的更多相关文章

  1. C#执行javascript代码

    最近在做网站自动登陆小工具,遇到技术屏障.密码在submit时会使用js进行加密.这时我需要模拟这个加密过程,想到使用C#执行javascript代码. 对于执行javascript代码,纯代码方式使 ...

  2. python中执行javascript代码

    python中执行javascript代码: 1.安装相应的库,我使用的是PyV8 2.import PyV8 ctxt = PyV8.JSContext()     ctxt.enter()     ...

  3. JAVA中执行JavaScript代码并获取返回值

    JAVA中执行JavaScript代码并获取返回值 场景描述 实现思路 技术要点 代码实现 测试方法 运行结果 改进空间 场景描述 今天在CSDN上偶然看到一个帖子对于一段字符串 “var p=‘xx ...

  4. Java执行JavaScript代码

    Java执行JavaScript代码 这篇文章主要为大家详细介绍了Java执行JavaScript代码的具体操作方法,感兴趣的小伙伴们可以参考一下 我们要在Java中执行JavaScriptMetho ...

  5. UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等)

    UWP 中使用 WebView 时可以在网页中额外执行一些代码.于是你几乎可以在网页上做任何事情,那些你可以在浏览器控制台中做的事情. 本文将介绍做法. 本文内容 准备环境 执行 JavaScript ...

  6. UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) - walterlv

    原文:UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) - walterlv UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) ...

  7. 尚学堂 215 在java中执行JavaScript代码

    package com.bjsxt.test; import java.io.FileReader; import java.net.URL; import java.util.List; impor ...

  8. 转:selenium webdriver 执行javascript代码

    在用selenium webdriver 编写web页面的自动化测试代码时,可能需要执行一些javascript代码,selenium本身就支持执行js,我们在代码中import org.openqa ...

  9. 如何正确的加载和执行 JavaScript 代码

    无论当前 JavaScript 代码是内嵌还是在外链文件中,页面的下载和渲染都必须停下来等待脚本执行完成.JavaScript 执行过程耗时越久,浏览器等待响应用户输入的时间就越长.浏览器在下载和执行 ...

  10. selenium webdriver ——执行javascript代码

    在代码中import org.openqa.selenium.JavascriptExecutor;就可以使用executeScript.executeAsyncScript这两个方法了 execut ...

随机推荐

  1. Redis - 对象结构

    简介 Redis 使用对象存储数据库中的键和值,每当在 Redis 中创建一个新的键值对时,都会创建两个对象:一个是键对象,另一个是值对象. 其中,Redis 的每种对象都由对象结构和对应编码的数据结 ...

  2. 在 Kubernetes 集群上部署 VSCode

    在 Kubernetes 集群上部署 VSCode Visual Studio Code Visual Studio Code 是一个轻量级但功能强大的源代码编辑器,可在您的桌面上运行,适用于 Win ...

  3. 一文彻底搞懂Raft算法,看这篇就够了!!!

    最近需要设计一个分布式系统,需要一个中间件来存储共享的信息,来保证多个系统之间的数据一致性,调研了两个主流框架Zookeeper和ETCD,发现都能满足我们的系统需求.其中ETCD是K8s中采用的分布 ...

  4. pandas之读取文件

    当使用 Pandas 做数据分析的时,需要读取事先准备好的数据集,这是做数据分析的第一步.Panda 提供了多种读取数据的方法: read_csv() 用于读取文本文件 read_json() 用于读 ...

  5. C++ 标准库 sort() / stable_sort() / partial_sort() 对比

    C++ STL标准库中提供了多个用于排序的Sort函数,常用的包括有sort() / stable_sort() / partial_sort(),具体的函数用法如下表所示: 函数 用法 std::s ...

  6. python:调用内置函数

    问题描述:尝试下博客园如何上传GIF # hzh 每天进步一点点 # 2022/5/13 17:24 import colorama import time import os colorama.in ...

  7. Spring Boot 中使用 Redis

    Redis 环境 redis 安装.配置,启动:(此处以云服务器上进行说明) 下载地址:https://redis.io/download/ 下载后上传到云服务器上,如 /usr/local 中 gc ...

  8. 详解C++中的extern与static关键字

    本章通过问答方式明晰两个关键字及其作用. Q1:对于int x:,不加extern关键字他就是个未赋初值的定义,但是如果加了static或者extern都可以表示这仅是一个声明吗? A:不是的,具体情 ...

  9. Django相关配置信息

    Django相关配置信息 1.配置数据库mysql 1.1 setting.py中配置信息 DATABASES = { 'default': { 'ENGINE': 'django.db.backen ...

  10. Java方法的返回值及注意事项

    方法的返回值 为什么要有带返回值的方法呢? 调用处拿到方法的结果之后,才能根据结果进行下一步操作 带返回值方法的定义和调用: 如果在调用处,要根据方法的结果去编写另一段代码逻辑 为了在调用处拿到方法产 ...