Bobolo
  • Home
  • Me

JavaScript Engine

对 Javascript Engine 的简单理解

13 Min Read

Thu May 05 2022

Written By Bobolo

Javascript Engine,JS 引擎在平时我们都或多或少听到过,例如页面解析过程,在解析到 Js Code 的时候就交由 Js 引擎来执行。那它到底是怎么个执行原理,JIT (just-in-time )又在其中做了什么事?

Javascript Engine 是一个计算机程序,计算机本身无法识别 JS,它执行 Js Code 并将其转换为计算机可理解的语言。它有点类似 React Components,Components 可以在 React 程序中 Import 使用,它也是可以在任何操作系统或平台上运行。

所有现代浏览器都内置 Js Engine,Chrome 的 V8、Safari 的 JavaScriptCore,Microsoft Edge 的 Chakra,最流行的是 Google 的 V8。但新出的 Bun 则是采用了 JavaScriptCore。

JS Engine Work

已经知道 Js Engine 是用来执行 Js Code 了,抛开优化等不谈,我们先来看看 Js Engine 在浏览器是如何工作的,或者说执行 JS 应该需要做什么事情。

  1. HTML 以及 Js File 中的 Js Code 可以理解为 String,需要把这些 String 进行识别
  2. 将这些识别到的 Js Code 编译为计算机可以识别的机器码

看起来好像 2 步就可以完成,但 Js Code 是无法直接编译机器码的,原因就如同平时开发的 React,是不能直接在浏览器执行的,需要 Babel 等工具把代码转 React.createElement 等代码才能被浏览器执行。所以 Js Code 也需要做一个中间的转换,这个东西就是 Bytecode 字节码。

因此 2 可以分解为,将识别的 Js Code 解释为字节码将生成的字节码编译为机器码,这也是最初的 Js Engine 的流程。

rudimentary

但是代码总是需要性能优化的,因此需要一些预编译、缓存、监听更新等功能。目前的 Js Engine 工作流程就更新成如下所示

  • Parser - 解析 HTML 或者 JS File 的 Js Code
  • AST - 将 JS 生成 AST
  • Interpreter - 生成字节码,删除 AST 释放内存
  • Profiler - 监听代码,在代码改动后可以快速生成新的
  • Compiler - 提前将生成的字节码编译为计算机可以识别的机器码.
  • Optimized code - 优化代码,如 JIT

Engine

Javascript Engine 主要是是阅读代码并执行它——即分配、使用和释放内存。因此需要一个地方来存储和写入信息——数据(变量、对象等),也需要跟踪代码运行情况。Memory Heap 则作为存储和写入信息的地方,包含程序中需要的对象。Call Stack 代码执行的地方,可以跟踪代码中的位置。

Javascript Runtime

Js Engine 具备了解析和执行 Js,但在浏览器上或者 Node 这些环境上,也需要一些它们特有的 Api,如 Web Api、Node Api,而这个不同的运行环境就是 Javascript Runtime。而 Runtime 主要就是给 Js Engine 增加特有 Api 的功能。

例如浏览器的正常运行,Js Engine 需要结合其他的组件才可以运行、它与其他组件一起运行的环境称为 JavaScript Runtime Environment(JRE)

  • JS Engine
  • Web API
  • Callback Queue or message queue
  • Event Table
  • Event loop

Engine

浏览器的多进程不单包括 Js Engine,还有 Gui、Http 等

V8 Engine

V8 Engine 是 Chrome 开发的也是最流行的 Js Engine,因此选择它来尝试性做一个 Runtime,方便更好的理解 Js Engine。

Implement

Rust 环境的详细配置就不一一说明了,管理工具用的 Cargo ,这些都可以直接跟着官网配置即可,主要是看 Rust 的代码逻辑即可。

以下是几个基本的概念:

  • v8::Platform,可以定制诸如内存页分配(PageAllocator),任务调度(NumberOfWorkerThreads、CallOnWorkerThread、IdleTasks、PostJob)等规则。
  • v8::Isolate,一个隔离的运行时环境,拥有自己的堆内存。多个不同的 Isolate 运行时可以并行执行,互不干扰,数据也完全隔离不可互相访问,就像多个沙箱。
  • v8::HandleScope,用来装 Handle(Local)的容器, Handle 分为 Local(局部,被 HandleScope 管理)和 Persistent(类似全局,不被 HandleScope 管理),JavaScript 的值和对象也都存放在 V8 的 Heap 中,Handle 是对 Heap 中对象的引用。
  • v8::Context,指的是 JavaScript 的执行环境,它包含了 JavaScript 代码执行所需的上下文信息,包括全局变量、函数等。一个 Isolate 中可以创建多个 Context,但 JavaScript 都必须执行在一个 Context 中。

Engine

Cargo run 后就可以得到 log 的结果,Result is: Object {"message": String("Hello from Rust!"), "status": Number(200)}

上面的是最简单的 Demo,Js 部份也没有什么功能和 Api,但是我们在浏览器或者 Node 都具备很多的 Api。这是增加了fetch Api 的简单 Demo

Conclusion

V8 Engine 是个挺有意思的内容,可以更好的去了解 Js 的执行还有加载等,所以去尝试做一下简单的 Demo,知道 JS 怎么运行以及那些 Api 是怎么处理,那其他的 Api 就是在这个基础上去添加,犹如 React 中添加 Component 一样,当然它还是复杂得多,有各种优化还有内容的考虑。

Reference

Powered by Bobolo

Copyright © Bobolo Blog 2021