大家好,这里是大家的林语冰。
《前端猫猫教》每日 9 点半更新,坚持阅读,自律打卡,每天一次,进步一点。
免责声明
本文属于是语冰的直男翻译了属于是,略有删改,仅供粉丝参考。英文原味版请传送 Should you use Bun or Node.js or Deno in 2024?。
本期共享的是 ------ 如何为我们的下一个大型项目选择正确的 JS 运行时!2024 构建 JS 筑基的现代 API 相对简单。我们可以使用 Express 等库,并在几分钟内启动可用的 API。但是,现在最具挑战性的部分是选择正确的 JS 引擎。
尽管备胎生态非常庞大,但我们必须了解三大 JS 运行时:
- Node
- Deno
- Bun
那么,我们应该为下一个大型 JS 项目选择什么运行时呢?事情没有那么简单。重要的是要了解每个运行时都有优缺点。因此,本文通过比较 Bun、Node 和 Deno 的优势和缺陷等来测评它们!
Node
Node 是用于服务器端开发最广泛使用的 JS 运行时。
Node 运行在谷歌 Chrome 的 JS V8 引擎之上,确保快如闪电且高度可靠的性能。Node 最有益的方面之一是事件循环(event loop)。
事件循环允许我们在单个线程上运行整个 App,而不会遭遇任何阻塞。它能够智能地将异步阻塞操作转移到第三方库 libuv 上,libuv 执行所有异步 I/O 操作,并让 Node 主线程在调用堆栈空闲时处理回调。此外,通过集成 worker 线程(工作者线程),开发者现在能够启动独立的 JS 运行时,并模拟多线程和并行处理。
Node 开发 API 的优势:
- 高度可扩展性和性能:Node 通过非阻塞 I/O 和可扩展性提供更高的性能,并由事件驱动架构支持,这使得 Node 非常适合用户群不断增长的实时数据密集型 App。
- 拥有众多库和框架的成熟生态系统:Node 拥有一个元气满满的生态系统,拥有丰富的库和框架,为开发者提供了一个全面的工具包,可以跨 Web 开发和实时 App 进行高效编码。
- 大型且活跃的社区支持:Node 拥有一个生机勃勃且元气满满的社区,可以转化为定期更新和改进、以及广泛发布的模块,开发者可以轻松地将这些模块合并到它们的项目中。
Node 开发 API 的缺陷:
- 单线程性质导致的性能瓶颈:由于 Node 是单线程的,因此它不适合繁重的计算,或需要 CPU 密集型的任务。虽然但是,引入 worker 线程后,Node 能够执行 CPU 密集型操作,而不会遭遇性能瓶颈。
- 异步编程中的回调地狱 :所谓"回调地狱",指的是 Node 中的异步函数彼此嵌套得深不见底,以至于代码变得复杂且混乱,就像试图捋顺一碗意大利面条一样。幸运的是,可以通过使用
Promises
和async/await
等解决方案来避免这种情况,这有助于使代码更清晰、更易于阅读。
Deno
Deno 是一种新兴的 JS/TS 运行时,致力于解决 Node 的某些缺陷。
Deno 默认优先考虑安全性。
在没有适当权限许可的情况下,这可以确保我们的代码无法访问文件或网络。Deno 运行在 JS V8 引擎之上,并采用 Rust 设计,这意味着它的速度快如闪电!
此外,Deno 还通过合并内置实用程序(比如用于网络的 fetch
)来采用当前的 Web 标准,与浏览器处理 JS 的方式保持一致,并提供更具凝聚力的编码体验。
Deno 开发 API 的优势:
- 内置安全性:Deno 在安全的沙箱环境中运行,需要明确的权限才能访问文件系统、网络和环境,从而降低漏洞风险。
- 改进的开发体验:Deno 通过依赖检查器和代码格式化等内置工具增强了开发者的工作流程,并提供原生 TS 支持,使开发者能够关注编码而不是配置。
- 使用 URL 简化模块管理:Deno 通过利用 URL 直接从 Web 获取依赖,而无需包管理器,简化模块管理,从而简化代码库中的模块解析。
Deno 开发 API 的缺陷:
- 不如 Node 生态系统成熟:Deno 作为 Node 的新潮备胎方案,正在开发其生态系统,预计通过社区贡献实现增长。与 Node 强大的生态系统相比,开发者目前看到的现成解决方案可能较少。
- 第三方库的可用性有限:虽然 Deno 正在不断发展,但其第三方库的选择并不像 Node 的宝库那么广泛。开发者可能会发现自己处于前沿,有时需要利用可用资源发挥创意,甚至需要自己制作资源。随着 Deno 生态系统的发展,库的数量将会增加,从而拓宽每个人的工具范围。
Bun
Bun 是 2023 推出的一个新兴的运行时和工具包。
Bun 是一个快速、一体化的工具包,用于运行、构建、测试和调试 JS/TS,从单个文件到全栈 App。
而且,有了 Bun,我们所要做的就是开箱即用。举个栗子,我们不再需要安装 nodemon/dot-env
等工具,因为 Bun 能够在开发者模式下开箱即用地热重载,同时默认也能选用 .env
文件。
此外,Bun 还提供内置的 websocket 服务器,并使用自己的包管理器 bunx,速度比 npm 快 5
倍。但是,这还不是全部。Bun 不仅仅是一个 JS 运行时。这是一个一体化的工具包。这意味着 Bun 还提供了开箱即用的功能:
- 打包功能
- 包管理器
- 测试运行器
因此,我们不需要花时间配置项目,也不需要维护复杂的样板项目。相反,我们可以启动一个 Bun 项目并立即开始!
Bun 开发 API 的优势:
- 简单的学习曲线:Bun 是一个一体化工具包!这意味着,我们不必花时间学习模块打包、配置测试框架。Bun 默认执行这些操作。这样我们就可以原地起飞!
- 更高的性能:Bun 使用 JavaScriptCore 引擎,而 Node、Deno 等运行时使用 JS V8 引擎。JavaScriptCore 引擎已针对更快的启动时间进行了优化,并且通常比其他两个运行时的性能更高。
Bun/ Bun Router 开发 API 的缺陷:
- 社区支持较少:Bun 才诞生不久。因此,Bun 仍然没有一个成熟的问题社区。如果我们严重依赖社区支持,那可能需要在继续之前检查是否有正确的支持。
Node vs Deno vs Bun
1. 性能跑分
让我们来测评一下 Bun、Deno 和 Node。
我们使用 JS 编写一些需要大量内存的数学代码来处理大数据集,考虑复杂计算和海量计算。
一个典型的例子是矩阵运算。这是一个矩阵乘法函数的示例,它在处理大型矩阵时大显身手。
js
function generateRandomMatrix(rows, cols) {
const matrix = []
for (let i = 0; i < rows; i++) {
matrix[i] = []
for (let j = 0; j < cols; j++) {
matrix[i][j] = Math.random()
}
}
return matrix
}
function matrixMultiplication(a, b) {
const rowsA = a.length
const colsA = a[0].length
const rowsB = b.length
const colsB = b[0].length
if (colsA !== rowsB) {
throw new Error('Incompatible matrices for multiplication')
}
const result = new Array(rowsA)
for (let i = 0; i < rowsA; i++) {
result[i] = new Array(colsB).fill(0)
}
for (let i = 0; i < rowsA; i++) {
for (let j = 0; j < colsB; j++) {
for (let k = 0; k < colsA; k++) {
result[i][j] += a[i][k] * b[k][j]
}
}
}
return result
}
const matrixSize = 1000 // Adjust the size of the matrix to increase memory usage
const matrixA = generateRandomMatrix(matrixSize, matrixSize)
const matrixB = generateRandomMatrix(matrixSize, matrixSize)
console.time('Matrix Multiplication')
const resultMatrix = matrixMultiplication(matrixA, matrixB)
console.timeEnd('Matrix Multiplication')
我们有 generateRandomMatrix
来创建任意大小的随机矩阵。然后是 matrixMultiplication
将这些矩阵相乘。我们可以使用 matrixSize
变量来决定这些矩阵的大小。
随着矩阵大小的增加,我们会注意到内存使用量也会随之增加。让我们看看 Bun、Node 和 Deno 如何使用此代码执行操作。
我们使用一个名为 hyperfine
的基准测试工具,准备好开始基准测试,让我们运行命令瞄一下会发生什么!
bash
hyperfine "bun index.js" "node index.js" "deno run index.js" --warmup=100 -i
上述 shell 命令会在不同的运行时执行上述代码,并且需要几分钟的时间才能提供基准测试结果。
Bun 在管理内存和 CPU 密集型任务方面的熟练程度不仅仅是巧合,它专为速度和最佳性能而设计。如果您的项目需要快速和高效,Bun 被证明是一个绝佳选择。
Bun 不仅与 Node 和 Deno 势均力敌,甚至还有过之而无不及。Bun 经常赶超它们。因此,如果您想构建一个能够在不牺牲功能的情况下提供速度和效率的 App,那么考虑 Bun 是一个值得的选择。
2. 社区比较
另一方面,社区支持对于已经存在了一段时间的运行时是有利的。举个栗子:
- Node:作为一个经验丰富的"骨灰级玩家",Node 拥有一个繁华的社区。这反映了 Node 在 API 开发中的由来已久且人见人爱。
- Deno:Deno 正在迅速开拓自己的市场。Deno 得到了一个元气满满、高瞻远瞩、渴望突破界限和创新的社区支持。
- Bun:Bun 社区相比前两者而言相对较小。这主要是因为 Bun 比它们更新。但是,根据 Bun 的发展方式,毋庸置疑,它很快就会拥有一个庞大的开发者社区!
但是,Node 脱颖而出,它在 API 开发方面的丰富经验培育了一个元气满满且生机勃勃的社区。这个技术爱好者社区始终准备提供协助、交换资源和协作。
尽管 Bun 和 Deno 正在取得长足进步,但 Node 社区仍然难以超越。因此,如果您优先考虑强大的支持网络,Node 是一个可靠的选择。
3. 安全性
Node、Deno 和 Bun 都有独特的安全方法。下面简单介绍一下它们的区别:
- Node :Node 默认对我们的系统开放,具体取决于可能引入风险的第三方包。
npm audit
等工具有助于捕获漏洞。举个栗子:
bash
npm audit
另外,使用像 helmet
这样的以安全为中心的中间件可以增强 Node App 的防御:
js
const helmet = require('helmet')
const app = require('express')()
app.use(helmet())
- Deno:Deno 就像一个保险库,脚本被紧紧锁定,除非我们明确授予权限。运行具有有限访问权限的 Deno 服务器,如下所示:
bash
deno run --allow-net=example.com server.ts
- Bun:这个新玩意的目标在于速度,并提供内置的安全功能。虽然但是,Bun 初出茅庐,因此它可能没有像其他方案一样经过那么多安全场景的测试。
显然,Deno 采取了高度宽松的方法,它对 App 拥有的权限持谨慎态度。Deno 以安全性为首要任务构建,在安全沙箱环境中运行,除非明确授权,否则限制文件和网络访问。
虽然 Node 和 Bun 结合了各自的安全措施,但 Deno 的附加内置安全层,使其成为在 API 开发中优先考虑安全性的首选。
因此,如果安全性是您的首要任务,请选择 Deno!
全都要,或是三选一?
前端开发没有银弹。这取决于您的优先事项。因此,收藏本文作为比较这些 JS 运行时的基准。
- Node:如果您关注"稳定至上",经过多年尝试和测试的稳定可靠的生态系统,那么 Node 是首选运行时。
- Deno:如果您关注"安全第一",以及最新的编程环境功能,建议使用 Deno。它还支持开箱即用的 TS。
- Bun:如果您关注"性能至上",尤其是在使用 JS/TS 时,Bun 应该是您的首选。
写在最后
2024 选择正确的 JS 运行时可能看起来令人头大,但了解 Bun、Node 和 Deno 的优缺点可以简化决策。
最终,您的项目的要求、对社区支持的依赖、以及对文档的准备程度,可能在确定最合适的选择中发挥关键作用。
本期话题是 ------ 你目前最常用哪个 JS 运行时,以及你预言未来哪个运行时会脱颖而出?
欢迎在本文下方自由言论,文明共享。谢谢大家的点赞,掰掰~
《前端猫猫教》每日 9 点半更新,坚持阅读,自律打卡,每天一次,进步一点。