关于node.js:快到飞起的Bun会替代Node吗

45次阅读

共计 8708 个字符,预计需要花费 22 分钟才能阅读完成。

背景

这段时间一个性能号称能够吊打 Node 和 Deno 的 JavaScript 运行时 Bun(包子) 横空出世,立刻在 JavaScript 社区闹得满城风雨。那么到底这个号称快到飞起的包子运行时到底几斤几两呢?这篇文章就让咱们通过一些理论的例子来理解一下 Bun 提供的性能以及它比 Node 到底快了多少,最初再探讨一下 Bun 是不是能够代替 Node。

什么是 Bun

咱们先来看官网形容:

Bun is a fast all-in-one JavaScript runtime

Bundle, transpile, install and run JavaScript & TypeScript projects — all in Bun. Bun is a new JavaScript runtime with a native bundler, transpiler, task runner and npm client built-in.

简略来说 Bun 是一个大而全的 JavaScript 运行时

它不止做了 Node 和 Deno 的工作 (JavaScript 运行时),而且还 原生 反对上面这些性能:

  • bundler: Bun 能够像 Webpack 等工具一样对咱们的我的项目进行打包
  • transpiler: 反对 TypeScript/JavaScript/JSX 的 Transpiling,换句话来说就是你能够在我的项目外面间接写 TypeScript 和 JSX 语法而不必放心配错环境了
  • task runner: 能够跑 package.json 外面的 script 脚本,相似于npm run xxx
  • 内置的和 npm 一样的包管理工具: 实现了和 npm,yarn 和 pnpm 等包管理工具一样的性能,不过更快

有同学看到这里能够会问:这些性能不是当初前端和 node 生态都反对了吗?有什么好学的?其实不然,Bun 的特色其实不在这些性能,而是在 原生 这两个方面。原生就意味着这是 Bun 自带的,咱们不须要写任何配置文件或者装置任何插件就能够用,这就升高了咱们编写代码的老本以及编写效率。而 Bun 另外一个特点是快,那它有如许快呢?看一些官网的形容:

从下面的形容能够看出这些数据:

  • Bun 的服务端渲染速度大略是 Node 的 3 倍
  • Bun 跑脚本的速度大略是 npm run 的 30 倍
  • Bun 的下载包的速度是 yarn 的 20 倍

听起来的确有点快,到底实际效果如何呢?接着就让咱们理论看一下。

Bun 性能介绍

这部分内容将会介绍 Bun 和 Node 或者 Node 生态其余工具如 npm 的比照,而不会波及到 Deno,因为 Deno 其实和 Node 的性能没有太大的区别。

Bundler 和 Transpiler

作为一个前端工程师,咱们常常须要应用 Webpack 等工具来对咱们的代码进行 transpile 和 bundle。和 Node 不同的是,Bun 原生就反对了 Bundler 和 Transipler 这些能力,而不必咱们额定装置其它依赖。除了这些,Bun 还内置了 React 脚手架的性能,你输出一个命令即可创立一个 React 利用:

bun create react ./react-app

下面的命令跑完后会生成一个这样目录构造的我的项目代码:

react-app
├── node_modules
├── README.md
├── bun.lockb
├── node_modules.bun
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
└── src
    ├── App.css
    ├── App.jsx
    ├── images.d.ts
    ├── index.css
    ├── index.jsx
    ├── logo.svg
    └── reportWebVitals.js

从下面的目录构造来看,应用 bun 创立的 React 利用非常清新,根本没有额定的配置文件,能够间接进行代码的编写。最重要的是,在笔者的渣渣电脑上跑这个命令只须要 6.55s!。而相比之下应用 npx create-react-app 跑了足足 四分钟 才创立出一个 React 我的项目来。换句话来说 Bun 创立一个 React 我的项目的速度是用 npm 通过 create-react-app 创立速度的 40 倍!单纯从这个速度上看,Bun 说本人快如闪电真的有余不为过。

下面生成的代码尽管只有 JS 文件,不过 bun 是原生反对 TypeScript Transpiler 的,所以你间接写 TypeScript 的代码也是能够运行的。

代码生成后,咱们能够通过 bun dev 命令来启动一个监听在 3000 端口的 带热更新 的 dev server。这个命令在我的电脑的执行工夫是 0.3s!,还没反馈过去服务就起来的。相同应用 create-react-app 创立的我的项目用npm start 耗时是25s。单纯看这个 case 的话,Bun task runner 是 npm task runner 的83 倍

在你开发完代码之后运行 bun bun 这个命令就能够对我的项目打包了,这个命令会打包出一个带有 .bun 后缀的二进制文件,这个命令大略执行了 0.1s,打包完的文件你间接扔到一个动态服务器就能够拜访了。而绝对之下,create-react-app 创立的利用运行npm run build 打包耗时28s,所以这个状况下,Bun 的速度是 npm 的 280 倍

这里值得一提的是,尽管 bun 打包文件绝对于应用 npm 来打包文件快的不止一个数量级,不过bun 还不反对 minify 和 tree-shaking 等常见的动态代码优化伎俩,这些都在它的 RoadMap 下面,前面会反对的。到时候加上了这些性能后还有没有这么快,就只能刮目相待了。

用 Bun 开发一个 Web 服务器

Bun 对 HTTP 服务的反对是很好的,你能够编写极其精简的代码来启动一个 Web 服务:

// http.js
export default {
  port: 3000,
  fetch(request) {return new Response("Hello World!")
  }
}

下面的代码会在 3000 端口启动一个 HTTP 服务,这个服务会返回一个 Hello World! 字符串。在笔者的电脑 (Macbook Pro 2.9GHz 双核 Intel Core i5 8GB 内存) 上应用 wrk 工具来测试一下这个服务的性能:

wrk -t 10 -c256 -d30s http://localhost:3000/

下面的命令会启动 10 个线程 256 个链接来间断测试咱们的接口 30s,最初失去的数据是:

Running 30s test @ http://localhost:3000/
  10 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    17.42ms   40.52ms 515.51ms   96.32%
    Req/Sec     2.33k   822.60     4.26k    65.55%
  660630 requests in 30.08s, 57.33MB read
  Socket errors: connect 0, read 3, write 0, timeout 0
Requests/sec:  21963.67
Transfer/sec:      1.91MB

咱们能够看到 Bun 原生的 HTTP 服务在我的电脑上的 QPS 能够达到 21963.67,那么咱们再来看一下 Node 的原生 HTTP 服务的性能能够到多少,代码如下:

const http = require('http')

const server = http.createServer((req, res) => {res.end('Hello World!')
})

server.listen(3000, () => {console.log('server is up')
})

下面的代码实现了和 Bun 的 HTTP 服务器一样的逻辑,只不过编写的代码多了一丢丢。在同样的电脑应用同样的参数来测试一下 Node 原生 HTTP 服务的性能失去的后果是:

Running 30s test @ http://localhost:3000/
  10 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    23.80ms   34.24ms 460.40ms   96.19%
    Req/Sec     1.31k   341.72     2.02k    82.15%
  376228 requests in 30.07s, 46.64MB read
  Socket errors: connect 0, read 58, write 1, timeout 0
Requests/sec:  12513.65
Transfer/sec:      1.55MB

从下面的后果能够看到,Node 原生的 HTTP 服务的 QPS 是 12513。单纯从这个测试后果来看,Bun 的性能大略是 Node 的 1.75 倍 。这么一看尽管 Bun 是快点,不过也没有很夸大。不过这可能也和机器无关,因为我看了一下一些国外博主的测试后果,他们电脑的性能比拟好,一样的测试代码,Bun 的 QPS 能够达到 200k,而 Node 只有 20k。 从他们的后果来看 Bun 的性能一下子比 Node 好了 10 倍,这真是质的飞跃了。所以在你的电脑上用 Bun 和 Node 实现一个简略的 HTTP 服务的性能差距又有多大呢?你还不放松试一下?

Bun 用作包管理器

下面提到了,Bun 内置了一个相似于 npm 的包管理器。应用 Bun 装置一个包 (moment.js) 的命令是:

bun install moment

下面的命令和 npm install moment 是一样的,会装置一个依赖到 node_modules 文件夹外面,这个命令在笔者电脑跑了2.6s,而后咱们再来跑一下 npm:

npm install moment

一样的电脑,npm 跑了差不多12s,单纯从装置 moment 这个包的速度来看,bun 的速度是 npm 的 4.6 倍。而国外博主个别测出的范畴是 4 到 80 倍,这应该是因为不同依赖安装时间不同导致的。总的来说,Bun 作为包管理工具来说真的比 npm 快了不少,至于和 yarn 以及 pnpm 比怎么样的话,有待读者本人验证并将后果留在评论区了。

Bun 作为 React 服务端渲染的解决方案

Bun 原生反对 React 的 server-side rendering,应用 Bun 实现一个最简略的 SSR 是这样的:

import {renderToReadableStream} from "react-dom/server"

const dt = new Intl.DateTimeFormat()

export default {
  port: 3000,
  async fetch(request: Request) {
    return new Response(
      await renderToReadableStream(
        <html>
          <head>
            <title>Hello World</title>
          </head>
          <body>
            <h1>Hello from React!</h1>
            <p>The date is {dt.format(new Date())}</p>
          </body>
        </html>
      )
    )
  },
}

拜访 localhost:3000 能够失去:

不过个别人应该不会这么裸写 SSR 而是用 NextJS 这种现代化的框架。Bun 也思考到这点,所以它也原生反对 Next 脚手架。应用上面的命令能够创立一个 Bun 的 Next 利用:

bun create next next-app

下面的命令跑了在我电脑跑了20s,而应用 npm 运行 create-next-app 跑了 10 分钟。单纯从这个速度上看Bun 是 npm 的 30 倍

下面的命令会创立一个监听在 3000 端口的 next 利用:

咱们同样尝试应用 wrk 来测试一下这个 Next 利用的并发性能:

wrk -t 10 -c256 -d30s http://localhost:3000/

测试过程中能够看到 Bun 利用在规范输入疯狂输入而后就奔溃了!没错是真的解体了

[603.38ms] / - 3 transpiled, 15 imports
[604.97ms] / - 3 transpiled, 15 imports
[613.77ms] / - 3 transpiled, 15 imports
[618.38ms] / - 3 transpiled, 15 imports
[621.86ms] / - 3 transpiled, 15 imports
[623.29ms] / - 3 transpiled, 15 imports
[648.52ms] / - 3 transpiled, 15 imports

SegmentationFault at 0x0000000000000000


----- bun meta -----
Bun v0.1.10 (fe7180bc) macOS x64 21.6.0
DevCommand: fast_refresh hot_module_reloading tsconfig filesystem_router framework public_folder bunfig 
Elapsed: 87754ms | User: 3341ms | Sys: 662ms
RSS: 127.34MB | Peak: 127.34MB | Commit: 67.15MB | Faults: 4894
----- bun meta -----

Ask for #help in https://bun.sh/discord or go to https://bun.sh/issues

具体起因不晓得,不过官网文档也说了当初 Bun 对 Next 只是Partial Support,也就是局部反对,咱们也就不深究起因了。接着咱们来看一下一个应用 Node 跑的 Next 利用:

而应用 create-next-app 创立的运行在 Node 的 Next 利用是能够通过 wrk 的测试的,后果如下:

Running 30s test @ http://localhost:3000/
  10 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   922.74ms  200.38ms   2.00s    78.20%
    Req/Sec    30.48     22.34   160.00     80.72%
  7635 requests in 30.09s, 31.90MB read
  Socket errors: connect 0, read 0, write 0, timeout 97
Requests/sec:    253.71
Transfer/sec:      1.06MB

Node 的 Next 利用 QPS 能够达到 253。这也得出一个论断就是 当初 Bun 还没有齐全反对 Next 的性能,并且很不稳固

Bun 一些其余的性能

因为文章篇幅无限,这里就不全副列出 Bun 所有的性能了,总的来说 Bun 还有上面这些性能值得读者去自行摸索:

  • bun:sqlite: Bun 内置的对 Sqlite 数据库操作,性能同样很好
  • bun:ffi: Bun 能够通过 ffi 调用任何反对 C ABI 的语言,例如 Zig, Rust 和 C /C++ 等
  • napi: Bun 反对 Node 90% 的 napi

Bun 为什么这么快

从下面笔者的理论应用成果来看,Bun 确实比 Node 快了不少,接着就让咱们摸索一下 Bun 比 Node 快的一些可能起因。

JavaScriptCore 代替 V8

这个是 Bun 官网给出的起因。Bun 应用了 Apple 的 JavaScriptCore 引擎而不是 Google 的 V8 引擎,JavaScriptCore 是 Safari 底层的 JS 引擎,和 V8 比起来嵌入老本高一点。至于 JavaScriptCore 是不是真的比 V8 性能好的话,这个真的很难判断,我在网上没找到一些不同 JS 引擎 Benchmark 的比照数据,反而是一些国外博主理论测试了一下 Hermes(Facebook 出品),JavaScriptCore 和 V8,发现性能上来说Hermes 略好于 JavaScriptCore 略好于 v8。不过也就差了一点点,这也和测试代码无关,如果大家能有一些理论的比拟权威的测试数据欢送在留言区评论。

应用 Zig 语言

这个也是 Bun 官网给出的起因,咱们先来看一下原话怎么说的:

Zig’s low-level control over memory and lack of hidden control flow makes it much simpler to write fast software.

它的意思是 Bun 快的一个起因是应用了 Zig 这门对内存有更低层次的管制和暗藏控制流的语言。诚实说要不是因为 Bun 我都不晓得有这个语言的存在。我 Google 了一下这门语言,它大略借鉴了 Rust 的一些思维,目标是想改良 C 语言,而且公布工夫十分短,最早公布于 2016 年,当初在 TIOBE 的语言受欢迎榜单连前 50 都没有。所以我对这门语言放弃了狐疑的态度

我认为的起因

诚实说官网给出的起因我感觉说服力是不够的。依我看来,可能是上面这些起因导致 Bun 目前性能好于 Node

  • Bun 还不成熟,很多工业级的性能都没有,等加上这些性能后是不是还比 Node 快真不知道
  • Bun 的目的性很强,一开始就晓得本人须要提供什么工具解决什么问题,所以它在设计的时候自然而然就会依据具体场景设计一些优化的计划,所以在某些场景下性能会长处,例如包治理等

Bun 相比 Deno 哪里做对了

和之前另外一个 Node 替代者 Deno 比起来,我感觉 Bun 做得对的中央有两点。一个是 兼容 Node 生态而不是新陈代谢。这一点其实很重要,因为从 Node 2009 年公布而来曾经在很多大公司应用实际了,领有微小的生态系统。Deno 一开始压根就没有想着兼容 Node,所以它的很多轮子都要从新造,并且现有 Node 利用迁徙起来十分困难,所以你看看 Deno v1 也公布了两年多了,该用 Node 的还在用 Node。不过侥幸的是,Deno 团队也意识到了这些问题,在 1.15 后容许你应用 std/node 来运行局部 Node 利用。和 Deno 不同,Bun 一开始就将兼容 Node 放在了第一位,尽管当初还没有做到齐全兼容 Node 的 API,不过这是它始终奋斗的指标,你想一下,如果有一天 Bun 做到 Node 利用无缝迁徙,还有 Deno 什么事吗?

Bun 做对的另外一个事是,它解决了一个 Node 生态的痛点,就是慢,特地是装置依赖和启动我的项目慢。这些是很重要也是很广泛的问题,所以它能够成为一个短缺的理由让 Node 开发者违心迁徙到成熟的 Bun。而相同 Deno 并没有解决这个问题,而是解决了一些我集体感觉不是那么广泛的问题,所以原来的 Node 开发者迁徙到 Deno 能源也就有余了。

Bun 可不可以代替 Node

Bun 和 Deno 比起来好那么多,那么是不是意味着它能够真正代替 Node 呢?先说论断,我感觉 Bun 不会代替 Node,最起码将来几年不会

在我看来,Bun 存在上面这些问题。

  • Zig 语言的局限性
  • All-in-one 的架构设计
  • 远不齐备的性能

Zig 语言的局限性

下面在说 Bun 为什么这么快的起因时有提到 Zig 语言是一门很年老而且并不受欢迎的语言。很年老就意味着这门语言可能还会存在很多没通过实际测验的 bug,不那么受欢迎就意味着这门语言的开发者群体少,也就意味着 Bun 的 contributor 的潜在开发人员少。这些起因都会妨碍 Bun 的倒退。

All-in-one 的架构设计

在日常工作中,我发现如果一个人什么都想做好的话,往往会导致他最初什么都没做好,究其原因是因为一个人的精力是无限的。

尽管我的项目不同于人,不过也能够进行类比。Bun 的指标很远大什么都想做,并且什么都想做好(你不做好他人也不会用)。这里有两个问题,一个是你真的是什么都能够做吗?依照官网的介绍来说 Bun 当初反对 JSX,可是 Vue 和 Angular 的 Transpile 形式是和 React 不一样的,除了这两个框架还有 Svelte 等等其余框架而且将来可能还有更多新的框架,你真的能够每一个框架都反对吗?另外一个问题是什么都想做好,后面提到 Zig 语言的时候就说了,这是一门不那么受欢迎的语言,也就是说很少这方面优良的编程专家,因而 Bun 前面开发起来预计会很吃力,总不能始终靠这几个人吧?既然开源进来了社区参加才是王道,而 Zig 语言的局限性就意味着能参加的优良开发会很少,品质自然而然就比拟难保障了。

相同我感觉 Bun 能够学习 Unix 的那种方法 having small independent tools that do one thing well and still can play together 的思维。换句话来说,就是不必什么都要做,而是提供一个相似于 bun-core 的外围,这个外围是一个 JS 运行时 + 包管理器,它保障了 Bun 飞快的 JS 运行速度,高效的包治理以及兼容所有的 NodeAPI,因为这些才是它的外围。而后 bun-core 对外提供 API 反对外界扩大它的性能,这部分扩大的性能由对应的社区开发者开发,这样 Bun 才不会最初变成一个什么都做不好的硕大无朋。

远不齐备的性能

我感觉 Bun 临时代替不了 Node 的最初一个起因是它目前还欠缺了很多外围的性能,所以远远达不到能够在生产环境应用的成果。在介绍 Bun 的 Transpiler 性能的时候,你也发现 Bun 还不反对 Minify 和 Tree-Shaking 等罕用的性能,其实不止这样,如果你看一下 Bun 的 RoadMap,你会发现它连百分之 20 的性能都没开发完,也就是说还须要很长很长的一段时间咱们能力在理论中应用。

总结

这篇文章我为大家介绍了一个全新的 JS 运行时 Bun,它最大的特点就是快,不过我感觉大家当初大略理解这个技术并放弃肯定的关注水平即可,不必那么焦急投入到学习中去,因为它将来的路线不确定性还是很大的,目前来说还代替不了 Node

集体技术动静

关注我的公众号 – 进击的大葱获取我的最新技术推送

正文完
 0