Please enable Javascript to view the contents

Bun.js 船新全能的现代 JavaScript 运行时

 ·  ☕ 4 分钟

啊!JavaScript Runtime 都卷起来了

现在的 JavaScript 给人风光无限的感觉,充满想象空间。但起先 JavaScript的解释器很慢,也只有浏览器一个运行时。

JavaScript作为一门图灵完备的语言,长久以来却限制在浏览器的沙箱中运行,它的能力取决于浏览器中间层提供的支持有多少。后来有了V8,有了 Node,JavaScript 可以随心所欲的访问本地文件,可以搭建WebSocket服务器端,可以连接数据库,可以如Web Workers一样玩转多进程,可以运行在不同的地方。

Node.js® 是一个基于 Chrome V8 引擎 的 JavaScript 运行时环境。

深入浅出Nodejs - 朴灵 图1-1 Chrome浏览器和Node的组件构成

Node 做大做强之后,也暴露出一些问题。2018年, Node.js 创始人 Ryan Dahl 发表演讲 “我在 Node .js 最后悔的 10 件事”,坦言 Node.js 有十大设计错误:

  1. 没用 JavaScript 异步处理的 Promise 对象

  2. 低估了安全的重要性

  3. 使用了 gyp 来设计 Build 系统

  4. 没有听大家的建议提供 FFI 而继续用 gyp

  5. 过度依赖 npm(内建 package.json 支持)

  6. 太容易造成 require(“任意模块”)

  7. package.json 建立了错误的模块概念(在同一目录下的文件就是同一模块)

  8. 臃肿复杂的 node_module 设计和下载黑洞(往往下载 npm 得花上非常久的时间)

  9. require(“module”) 时没有强制加上 .js 扩展名

  10. 无用的 index.js 设计。

随后, Ryan Dahl 打造了全新的服务器端 JavaScript 运行环境 Deno。

Deno 跟 Node.js 一样都采用了 Chrome 的 JavaScript 引擎 V8,但 Deno 采用了更严格的 JavaScript 语法规范 TypeScript,Deno 等于是一个 TypeScript runtime。第一个版本的 Deno runtime 是用 Go 语言实现的,但是 Ryan Dahl 又重新用 Rust 语言开发了一次 Deno 的 runtime,避免因为重复使用两套垃圾回收器(Go 语言一套、V8 引擎也内建了一套)而影响效能。另外,Deno runtime 中也内建了 TypeScript 编译器。

Deno自2018年发布到现在也有4年了,好像敢没听说过什么明星项目。前一段推出了面向下一代WEB开发框架 fresh,心想 Deno 是不是真的要开始摧毁 Node 了?没想到,螳螂捕蝉,黄雀在后。最近新出的 Bun.js JavaScript 运行时,性能完爆 Node.js 和 Deno。

Bun.js

bun.sh

Bun 是采用 Zig 语言编写的高性能 “全家桶” JavaScript 运行时,官方称其为 “all-in-one JavaScript runtime”。

所谓 “all in one”,是因为 Bun 提供了打包、转译、安装和运行 JavaScript & TypeScript 项目的功能,内置原生打包器 (native bundler)、转译器、task runner、npm 客户端,以及 fetch、WebSocket等 Web API。

运行时 js引擎 编写语言
Bun JavaScriptCore Zig
Deno V8 Rust
Node V8 C/C++

值得注意的是(还真需要注意),实现bun的编程语言(系统级编程语言)不是c++,也不是rust,而是zig。

Zig 是一门系统级编程语言,专为稳定性、可维护性和性能而设计,追求替代 C 语言在系统编程上的最佳地位。这可能也是Bun号称比Node和Deno快的原因之一。

性能测试(快速排序)

Bun.js 在官网上列出了性能对比测试图,Bun 可谓是完爆 Node.js 和 Deno。这里我转载群友 𝙳𝚘𝚌𝚝𝚘𝚛🤓做的快排测试。虽然不是很科学,仅供参考。

测试代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
console.time()

const makeArr = (length) => {
    let arr = [];
    for (let i = 0; i < length; i++) {
        arr.push(Math.floor(Math.random() * length));
    }
    return arr;
}


const quicksort = (arr) => {
    if (arr.length <= 1) return arr;
    let pivot = arr[0];
    let left = [];
    let right = [];
    for (let i = 1; i < arr.length; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }
    return quicksort(left).concat(pivot, quicksort(right));
}

let length = process.argv[2];
// let length = 1000;
let arr = makeArr(length);
// console.log(arr);
const newArr = quicksort(arr);
// console.log(newArr)

console.timeEnd();

代码准确性测试

就是看看排序是否正确。

快速排序准确性测试

性能测试

生成长度为1000、10000、100000、1000000、10000000万数组进行排序,查看排序时间。(本想生成1亿长度的数组,电脑内存不够)

Bun.js

bun.js 快排测速

Node

Node 快排测速

Deno

Deno 快排测速

测试不是很精准,抛开runtime和executeTime的区别,本好测试的环境也不一样。bun是在wsl下运行的,而node与deno是在windows下执行。而deno因我不知道怎么使用 process 对象,所以数组长度是硬编码,而不是读取命令行参数。

最终结果三者速度差不多,Bun.js 在排序百万、千万长度数组时稍稍快一丢丢。

个人感想

学习一门新语言、新框架、新轮子会有一定时间成本,也有学得很好、学得很深但因为该语言不是主流而没办法应用到生产环境的风险。

不过新的框架也有一定的后发优势,比如没有以前框架的历史包袱技术债务、内置的组件库多、工具链完整等。

我个人会多花时间学习使用Bun.js,并希望它能做大做强。因为我在Node的积累是幼稚园水平,差同行太多。换个框架,或许还有追赶的机会。

参考资料

分享

码中人
作者
码中人
Web Developer