乐趣区

关于前端:JS三大运行时全面对比Nodejs-vs-Bun-vs-Deno

全文约 5100 字,预计浏览须要 15 分钟。

JavaScript 运行时是指 执行 JavaScript 代码的环境。目前,JavaScript 生态中有三大运行时:Node.js、Bun、Deno。老牌运行时 Node.js 的霸主位置正受到 Deno 和 Bun 的挑战,上面就来看看这三个 JS 运行时有什么区别!

JS 运行时概述

Node.js

Node.js 在 2023 年被 Stack Overflow 开发者评为最受欢迎的 Web 技术。Node.js 于 2009 年推出,容许开发人员在浏览器之外应用 JavaScript,彻底改变了服务端编程。它领有弱小的生态系统、宏大的社区,并且通过验证且稳固。为大型应用程序提供 LTS 构建。基于 V8 JavaScript 引擎构建。

多年来,Node.js 始终是服务端 JavaScript 开发的支柱,通过第三方工具反对了有数性能。其提供了微小的性能和灵活性。丰盛的文档、教程和社区反对使开发者能够更轻松地克服挑战。如果思考内置工具和与 Web API 的兼容性,它是落后于其余两个运行时的。

从历史上看,Node.js 因其平安办法(尤其是在包方面)而受到批评。然而,社区和维护者曾经显着改善了这一方面。权限模型曾经在 Node.js v20 中实现,这使 Node.js 更加平安。

Deno

Deno 最后由 Node.js 的原始创建者 Ryan Dahl 于 2018 年创立,旨在解决他认为 Node.js 中存在的一些问题,比方性能、安全性。它专一于安全性、古代 JavaScript 实际和开发人员体验。基于 V8 JavaScript 引擎构建并用 Rust 编写。

与 Node.js 相比,Deno 具备更全面的性能。它对 Web API 和古代规范有很好的反对,并且还反对大多数 NPM 包。Deno 还提供了杰出的开发体验,特地是如果应用 TypeScript,它是开箱即用的。Deno 还具备内置 linting、代码格式化程序等劣势,节俭一些配置和疏导工夫。如果你偏向于开箱即用的设置,只需启动编辑器,创立一个 main.ts 文件,而后就能够开始高兴编码了!

Bun

Bun 是 2021 年公布的 JavaScript 运行时,它被设计为 Node.js 的更快、更精简、更古代的替代品。它构建在 JavaScript Core 和 Zig 之上。旨在成为一个全功能的运行时环境和工具包,重点关注速度、打包、测试和与 Node.js 包的兼容性。最大的劣势之一是它的性能。事实证明,Bun 比 Node.js 和 Deno 都要快。如果 Bun 可能实现这些指标,那么它将成为一个十分有吸引力的抉择。

Bun 的外围卖点是它的 性能,其提供了许多基准测试,显示出令人惊叹的速度。应用 Bun 作为包管理器比应用规范 NPM 命令要快得多。在事实利用中,尤其是 Web 利用,性能差别可能不像基准测试中那么显着。

Bun 优先思考简略性和速度。凭借其内置的包管理器,以及与 Node.js 相比改良的开发体验,开发人员能够疾速入门,而无需遇到其余运行时可能带来的初始设置障碍。

性能比照

首先来看看这三个运行时的性能比照,图示如下:

  • ✅:内置,指自身提供的性能或个性,无需额定装置或引入其余库或框架。
  • 📦:通过第三方提供的库、框架或工具反对。
  • ❌:不可用。
  • 💡:试验个性。

运行时个性

个性 Deno Bun Node.js
降级工具
单个可执行文件装置
LSP
REPL 📦
编译器
长久存储驱动程序
  • 降级工具:更新和治理我的项目所依赖的软件包和库。
  • 单个可执行文件装置:将所有程序文件和依赖项打包成一个独自的可执行文件,以便用户能够简略地通过运行该文件进行装置和部署。
  • LSP(Language Server Protocol,语言服务器协定):一种用于提供代码编辑器性能的通信协议。它使得编辑器能够与语言服务器进行交互,从而取得代码补全、跳转到定义、重构等性能。
  • REPL(Read-Eval-Print Loop,读取 - 求值 - 输入循环):一种交互式编程环境,在其中能够逐行输出代码,并立刻执行并输入后果。REPL 通常用于疾速测试和验证代码,无需编译和构建过程。
  • 编译器:是一种将高级编程语言源代码转换为低级机器代码或字节码的工具。编译器将代码进行词法剖析、语法分析和转换等解决,最终生成可执行文件或中间代码,以供计算机执行。
  • 长久存储驱动程序:一种软件组件或接口,用于与长久化存储介质进行交互和治理数据的读取和写入操作。它提供了对长久化数据的拜访和操作的接口。

测试

个性 Deno Bun Node.js
基准测试运行器 💡 💡
测试运行器
  • 基准测试运行器:用于运行基准测试的工具或框架。基准测试用于评估代码的性能和效率,通常通过执行一系列测试用例并测量其执行工夫来进行。
  • 测试运行器:用于治理和运行测试套件的工具或框架。它能够自动化执行单元测试、集成测试或端到端测试,并提供后果报告和日志记录等性能。

操作系统 / 平台反对

个性 Deno Bun Node.js
Linux
Mac OS
Windows 💡
ARM64 💡 💡

包管理器

个性 Deno Bun Node.js
package.json 兼容性
NPM 勾销抉择
内置包管理器 📦 📦
URL 引入
  • package.json 兼容性:指我的项目中的 package.json 文件与特定工具、平台或环境的兼容性。package.json 是用于形容和治理我的项目依赖和配置的文件。
  • NPM 勾销抉择:在应用 NPM 作为包管理器时,抉择不应用某个特定的性能或设置。这可能是依据我的项目需要或集体偏好,无意抉择不采纳某种性能或行为。
  • 内置包管理器:集成在特定开发环境或平台中的默认包管理器。这个包管理器通常提供了一套工具和命令,用于下载、装置、更新和治理我的项目的依赖项。
  • URL 引入:通过提供近程资源的 URL 地址来导入模块或库的性能。应用 URL Imports 能够从近程地位间接引入代码或资源,而无需当时下载和装置。

Web API 兼容性

个性 Deno Bun Node.js
Fetch
Web Crypto
Web Storage
WebSocket 📦
Web Workers
Import Maps
  • Fetch(Fetch):一种用于发动网络申请的古代 JavaScript API。它提供了一种更简洁和弱小的形式来进行数据申请和响应解决,取代了传统的 XMLHttpRequest 办法。
  • Web Crypto(Web 加密):一组用于在 Web 浏览器中执行加密操作的 API。它提供了一种平安的形式来解决密码学操作,例如生成随机数、进行加密和解密等。
  • Web Storage(Web 存储):用于在客户端浏览器中存储和检索数据的 API。它提供了本地存储和会话存储两种机制,别离用于长期保持数据和长期存储数据。
  • WebSocket:一种在客户端和服务器之间实现双向通信的协定。通过 WebSocket,能够建设持久性的连贯,并实现实时数据传输和交互。
  • Web Workers:一种在浏览器中应用多线程进行并行计算的机制。Web Workers 容许在后盾运行脚本,以防止主线程的阻塞,并进步 Web 利用的响应性能。
  • Import Maps(导入映射):一种在 JavaScript 模块加载器中配置模块门路和别名的性能。导入映射能够简化模块导入的过程,并提供更灵便的形式来治理模块依赖。

安全性

个性 Deno Bun Node.js
权限模型
可信赖的依赖项
  • 权限模型:利用中用于治理用户或利用对资源和性能的拜访权限的零碎。权限模型定义了不同级别的权限和许可规定,并确保只有被受权的实体能力执行特定操作。
  • 可信赖的依赖项:开发中应用的第三方库或模块,曾经失去验证和认可,能够释怀地被我的项目所应用。可信赖的依赖项通常具备良好的安全性、稳定性和质量保证。

开发工具

个性 Deno Bun Node.js
代码格式化工具 📦 📦
动态代码剖析工具 📦 📦
类型查看工具 📦 📦
代码压缩工具 📦 📦
代码打包工具 📦
依赖项查看器 📦 📦
  • 代码格式化工具:用于主动调整代码的格局,例如缩进、空格和换行符等。通过应用代码格式化工具,能够对立代码款式,进步代码的可读性和一致性。
  • 动态代码剖析工具:用于查看源代码中的潜在问题、谬误或不良实际。动态代码分析器会对代码进行扫描,并给出相应的提醒或正告,帮忙开发人员发现并修复问题。
  • 类型查看工具:用于动态查看编程语言中的类型谬误。通过类型查看工具,能够在编译或运行前捕捉到类型相干的谬误,从而进步代码品质和可靠性。
  • 代码压缩工具:用于减小源代码文件的大小。代码压缩工具通常会移除源代码中的空白字符、正文和不必要的字符,从而升高文件大小,并进步加载速度。
  • 代码打包工具:用于将多个模块或文件打包成一个或多个最终部署的文件。通过应用代码打包工具,能够缩小网络申请次数,进步前端利用的性能和加载速度。
  • 依赖项查看器:用于查看我的项目或利用中的各个依赖项之间的关系和依赖状况。依赖项查看器能够帮忙开发人员理解我的项目的依赖构造,以便更好地治理和保护依赖关系。

语言反对

个性 Deno Bun Node.js
TypeScript / TSX 📦

性能比照

接下来看看这三个运行时的网络性能比拟。重点关注:动态文件传递、JSON 响应和计算密集型工作(素数计算)。

  • 动态文件传递:提供动态资源服务,将服务器上指定目录中的动态文件传递给客户端。
  • JSON 响应:接管客户端申请,生成蕴含 JSON 数据的响应并返回给客户端。
  • 计算密集型工作:接管客户端传来的数值,执行大量的 CPU 计算操作来判断该数是否为质数,并将后果返回给客户端。

为了进行精确的比拟,构建了一个自定义的基准测试工具,并应用 Express.js 作为服务端平台。Express.js 是一个很好的抉择,因为能够在所有三种运行时中应用完全相同的服务端脚本。源代码能够在 GitHub 上找到:jsrbench。为了对服务端增加负载,这里应用了 Siege,这是一个通过试验和测试的网络服务器基准测试实用工具。

上面是用于基准测试的服务端脚本:

import express from "express";



const app = express();



// 应用 BigInt 进行批改,并移除 NaN/Infinity 查看

const checkPrime = function (n) {if (n % 1n || n < 2n) return 0;

  if (n == leastFactor(n)) return 1;

  return 0;

};



const leastFactor = function (n) {if (n == 0n) return 0;

  if (n % 1n || n * n < 2n) return 1;

  if (n % 2n == 0) return 2;

  if (n % 3n == 0) return 3;

  if (n % 5n == 0) return 5;

  for (let i = 7n; i * i <= n; i += 30n) {if (n % i == 0n) return i;

    if (n % (i + 4n) == 0) return i + 4n;

    if (n % (i + 6n) == 0) return i + 6n;

    if (n % (i + 10n) == 0) return i + 10n;

    if (n % (i + 12n) == 0) return i + 12n;

    if (n % (i + 16n) == 0) return i + 16n;

    if (n % (i + 22n) == 0) return i + 22n;

    if (n % (i + 24n) == 0) return i + 24n;

  }

  return n;

};



// 动态资源中间件

app.use("/static", express.static("public"));



// JSON 响应

app.get("/json", (req, res) => {

  res.json({

    message: "Hello, World!",

    number: 5,

    literal: `(${4}+${4})*${21.2}/${2}=${84.8}`,

  });

});



// 模仿 CPU 密集型操作

app.get("/compute-prime", (_req, res) => {

  const toCheck = 263n;

  if (checkPrime(263n)) {res.send(`Prime number ${toCheck} is a prime!`);

  } else {res.send(`Prime number ${toCheck} is not a prime!`);

  }

});



// 将端点收集到数组中

const endpoints = ["/static/index.html", "/json", "/compute-prime"];



// 通过提供 '0' 主动调配端口

const server = app.listen(0, () => {

  const fullEndpoints = endpoints.map((endpoint) => `http://127.0.0.1:${server.address().port}${endpoint}`,

  );

  console.log(JSON.stringify({BENCHMARKABLE_ENDPOINTS: fullEndpoints,}));

});

10 个并发用户(每秒申请数)

门路 Node.js Deno Bun
动态文件传递 1712.37 1761.87 2559.35
JSON 响应 2223.57 2772.39 4138.38
计算密集型工作 2377.44 3480.13 4321.48

100 个并发用户(每秒申请数)

门路 Node.js Deno Bun
动态文件传递 2153.87 2571.72 3468.01
JSON 响应 2344.44 3468.01 4555.89
计算密集型工作 2286.53 3609.09 4341.41

依据给定的条件和具体的基准测试运行后果:

  • Deno 比 Node.js 快大概 33%。
  • Bun 比 Node.js 快大概 73%。

Bun 官网也给出了一个基准测试的数据:

  • React 服务端渲染(每秒 HTTP 申请数(Linux x64)):
  • WebSocket 聊天服务器(每秒发送的音讯数(Linux x64,32 个客户端)):
  • 加载一个微小的表(每秒均匀查问次数)

能够看到,Bun 是 Deno 的速度两倍,是 Node.js 速度的四倍。

反对和社区

这三个运行时都是开源的,但并非所有我的项目都齐全失去社区的反对。Node.js 由 OpenJS 基金会反对,并且严格以社区和志愿者为根底。Deno 和 Bun 失去了营利性组织和风险投资反对的我的项目的反对。

Node.js 有一个成熟的生态系统和宏大的社区。相比之下,Deno 和 Bun 则较为新鲜,遇到问题时可能解决难度更大,但依然有很多激情的开发者违心分享相干常识。此外,Deno 1.28 引入了更好的与 npm 包兼容性,使得从 Node.js 迁徙过去的开发者更容易接受。

上面是 Stack Overflow 上每个运行时标记的问题的数量(截至 2023 年 9 月):

运行时 问题数量
Node.js 466762
Deno 917
Bun 52

如你所见,Node.js 相干的问题最多,这也意味着当遇到问题时,更容易失去解决方案。

在 2022 年 State of JavaScript 考察中,有一个问题是对于参与者常常应用哪种运行时,有将近 30000 名受访者答复了这个问题。考察结果显示,Node.js 遥遥领先,Deno 得票数约为 5300,Bun 得票数约为 1200。兴许咱们会在 2023 年看到 Deno 和 Bun 呈现一些新的趋势。

官网的 Node.js 文档包含各种指南、大量的 API 参考和入门信息。还提供了无关其依赖关系的信息。

Deno 的网站包含一个十分具体的手册,帮忙你相熟运行时并在我的项目中开始应用它。第三方模块页面很不便,能够理解生态系统中可用的内容。截至 2023 年 8 月,它蕴含了超过 6000 个模块,并提供一些示例代码。

Bun 的主页链接到了其 Discord、文档和 GitHub 页面。自从它公布以来,文档曾经显著改善。当初官网文档中蕴含了各种主题的信息,例如入门指南、应用打包器和测试运行器以及 API 参考,甚至还有指南展现如何应用 Bun 实现常见工作。

从 Node.js 迁徙到 Deno 或 Bun

用纯 JavaScript 或 TypeScript 编写的代码应该能够在任何运行时无缝运行。然而,如果应用过 Node.js 的特定性能,那么迁徙到其余运行时可能会比拟艰难。

从 Node.js 迁徙到 Deno

过来,Node.js 模块的兼容性是 Deno 迁徙中的一个次要问题。不过,当初只需在导入语句前加上 node: 前缀即可。至于 npm 包,能够在它们后面加上 npm: 前缀,或者创立一个 deno.js 文件,形容 import maps[1] 以供 Deno 解析它们。

如果正在构建软件包 / 库,能够查看 Denoify[2]。这是一个旨在在迁徙时主动更改某些文件,并使我的项目保护更加容易,实用于 npm 和 deno.land/x[3] 的我的项目。

从 Node.js 迁徙到 Bun

Bun 实现了大多数 Node-API 函数。如果我的项目较小或仅应用常见函数,可能能够间接将其放入 Bun 中并开始应用。对于大型项目,可能须要重写代码来解决挑战。

Bun 还具备本人的 API。例如,Bun 应用本人的 API 来提供 Web 文件服务。

Bun.serve({fetch(req) {return new Response("Hello!!!");

  },

  tls: {key: Bun.file("./key.pem"),

    cert: Bun.file("./cert.pem"),

  }

});

能够看到,在迁徙到 Deno 或 Bun 时,应用它们的原生 API 就意味着代码与在 Node.j s 中应用的代码有所不同。这是在转换现有我的项目时须要牢记的重要事项,同时在开始新我的项目时也要思考到,因为如果遇到在 Node.js 中不存在的且难以解决的问题,可能会难以回退到 Node.js。

总结

Bun 显然是速度上的赢家,并且在性能上带来了很多翻新。但因为它依然很新,所以应用它存在危险。

Node.js 的一大劣势在于其成熟度和生态系统的规模。其依然是目前最平安的抉择,并久经考验。

与 Node.js 相比,Deno 还具备很多劣势,其弱小的性能使开发更加顺畅,并且能够轻松构建高质量的简单我的项目。它很平安,尽管比 Node.js 更快,但与 Bun 相比,它还是有点慢的。

总的来说,Node.js 依然是目前最好的抉择,Deno 具备很多现代化的性能,值得尝试。如果最关怀速度或只是想理解新技术的前沿,那么 Bun 就是你的首选工具。

[1]import maps:https://deno.land/manual@v1.36.1/basics/import\_maps

[2]Denoify:https://github.com/garronej/denoify

[3]deno.land/x:https://deno.land/x

往期举荐

VS Code 中应用 Git 实际,学会了效率翻倍!

微软最热门的 10 款前端开源我的项目!

JavaScript 终于原生反对数组分组了!

Next.js 13.5 正式公布,速度大幅晋升!

多图预警,前端应该把握的浏览器调试技巧大揭秘!

居然能够在一个我的项目中混用 Vue 和 React?

图解 60 个 CSS 选择器,一网打尽!

退出移动版