JS运行时漫谈
就在前几天,Bun 1.0发布了。它号称是一款全能的工具集,能够取代Node.js。从1994年发布第一款商业浏览器Netscape浏览器到如今已经过去了29年。在前端技术不断演进的今天,让我们回顾一下浏览器的历史以及JavaScript的各种运行时。
我们先看看各大浏览器的内核
浏览器 | 渲染引擎 | JS引擎 |
---|---|---|
Google Chrome | Blink(最早fork自WebKit) | V8 |
Mozilla Firefox | Gecko | SpiderMonkey |
Apple Safari | WebKit | JavaScriptCore |
Microsoft Edge | Blink (Chromium) | V8 |
Opera | Blink | V8 |
Internet Explorer | Trident (旧版本) | Chakra (旧版本) |
Microsoft Edge (旧版) | EdgeHTML (旧版本) | Chakra (旧版本) |
需要注意的是,很多浏览器都会基于自身来做自己的JS引擎,或者做一些封装,实现各不一样。
你知道,第一款JS引擎是什么吗?
是SpiderMonkey🤣! SpiderMonkey是世界上第一款JavaScript引擎,由JS之父-前网景公司的布兰登·艾克设计;现在也是Mozilla Firefox网页浏览器所使用的JavaScript引擎。
想想Java的运行过程
- javac xxx.java 编译为xxx.class,xxx.class是二进制字节码文件,包括了类的结构、方法、字段、指令等信息
- java xxx:
- jvm加载 .class文件;
- 验证、解析、初始化、执行
关于JVM:
1.它做了各平台适配,所以java支持跨平台
2.JVM 还支持即时编译(Just-In-Time Compilation,JIT)以提高性能: JIT是将字节码编译为本地机器码
tips: 汇编语言不是机器语言,它通过汇编器转换成机器码(机器码是硬件可以直接执行的指令)。
我理解 .class文件内容就像js的ast,是一种可读的DSL,只不过他是二进制而已;js的AST再通过字节码编译器也会变为二进制。
Webkit与JSCore
WebKit 渲染引擎是什么?
Webkit是苹果公司推出的浏览器引擎也叫内核,包含WebCore和 JavaScriptCore(简称JSCore); 最初主要用于safari浏览器中。
我们常说的HTML和CSS的解析就是WebCore来做的; JSCore的话就是负责网页上的 JavaScript 代码的执行;
另外在IOS和macOS app中,JSCore还会用来创建Webview.
JSCore对Js执行的工作流程:
词法分析 – Lexer: 主要就是分词,把源代码分成一个一个的token, 比如 “a” ”+” “b” ”=” “c” https://github.dev/WebKit/WebKit 这个网站 可以找到Lexer.cpp 文件查看源码
语法分析 – Parser: 这个就是基于token来获得AST了。(有点像babel编译ES6的过程)
ByteCodeGenerator: 根据AST来生成JSCore的字节码,完成整个语法解析步骤; 这个阶段会生成二进制字节码,有点像java的xxx.class
解释执行: 这个阶段JSCore就像JVM一样,利用JIT技术来生成机器码并立刻执行。
关于JIT
背景: 不同于C和C++的提前编译为机器码,JS和Python这样的动态语言因为在执行之前不能知道确切的类型,所以js是使用解释器来进行编译,但速度比较慢,然后就产生了JIT技术来提高效率。
V8、JSCore、SpiderMonkey具体的流程和逻辑不尽相同:
JSCore
在字节码=> 机器码阶段进行分析,检测哪些部分的代码被使用最多,然后将它们发送给JIT进行编译和存储。
V8
在字节码=>机器码阶段,会利用Ignition 字节码解释器配合Turbofan编译器从字节码来优化代码,然后再产生高度优化的机器代码。
它主要是对变量类型作合理推测并对多次重复运行的代码作优化存储,具体可以看这篇文章
chromium与V8
Chromium是Chrome的开源版本项目,比起Chrome它缺少了Google update、错误报告等谷歌集成产品的功能。
Tips: 之前网上吵的沸沸扬扬的国产红芯浏览器其实就是基于Chromium的。
Chromium 的架构
- Blink web 引擎(最早从Apple 的webkit项目 fork出来,然后继续自行开发)
- V8 JS引擎
- GPU硬件加速
- IPC进程间通信
- …
Chromium使用了多进程模型来保证浏览器的稳定性,比如标签页(每个标签页一个进程,但同域名的页面会共享一个进程)、三方插件、GPU加速进程等。
Chromium 在前端领域的使用
- Electron 基于Node.js,使用Chromium 作为其渲染引擎, 使得前端可以开发跨平台桌面端应用
- Puppeteer能通过脚本控制Chromium,通常它用来做屏幕截图、自动化测试等服务
Deno、Node与Bun
这几个JS的运行时项目都是开源的,Github可以直接找到
运行时 | 底层依赖 | 语言 | 其他说明 |
---|---|---|---|
Node.js | V8,libuv | C++、JavaScript | libuv操作文件系统、Socket等; V8作为解释器将Js代码编译为底层机器码 |
Deno | V8引擎 | Rust、JavaScript、TypeScript | Deno是Node.js原作者为解决Node痛点如回调语法、不支持TS等问题重新创造的,基于V8,使用Rust和文件系统、网络访问进行通信 |
Bun.js | WebKit引擎 | Zig、C++、TypeScript | 比较惊艳的是它不使用V8,而是依赖了Apple的WebKit引擎, 是一个all in one 的toolkit:能作为运行时、能作为打包器、能作为包管理器等。 |
部分图片源自网络,如有侵权请联系作者删除。
相关链接
https://tech.meituan.com/2018/08/23/deep-understanding-of-jscore.html
https://github.com/chromium/chromium
https://hacks.mozilla.org/2017/02/a-crash-course-in-just-in-time-jit-compilers/
https://www.freecodecamp.org/chinese/news/javascript-under-the-hood-v8/
https://mp.weixin.qq.com/s/jNynCQMd1g9-e_VzlKvA5g JavaScript 是怎么运行起来的?
https://zhuanlan.zhihu.com/p/27628685 认识 V8 引擎
https://zh.wikipedia.org/wiki/SpiderMonkey