Deno 1.25 已发布,包含以下新特性和变更
如果您已经安装了 Deno,可以通过运行以下命令升级到 1.25
deno upgrade
如果您是首次安装 Deno
# MacOS and Linux
curl -fsSL https://deno.land/x/install/install.sh | sh
# Windows
iwr https://deno.land/x/install/install.ps1 -useb | iex
点击此处查看更多安装选项。
deno init
子命令
使用 Deno 启动新项目一直以来都非常简单:您只需要一个文件即可开始。无需任何配置文件、依赖清单或构建脚本。
来自其他生态系统的用户通常不习惯这种简单性——他们常常寻找一个工具来搭建基本的项目结构,以帮助他们走上正确的轨道。在此版本中,我们添加了 deno init
子命令,用于搭建一个基本的 Deno 项目。
$ deno init
✅ Project initialized
Run these commands to get started
deno run main.ts
deno test
$ deno run main.ts
Add 2 + 3 = 5
$ deno test
Check file:///dev/main_test.ts
running 1 test from main_test.ts
addTest ... ok (6ms)
ok | 1 passed | 0 failed (29ms)
此子命令将创建两个文件(main.ts
和 main_test.ts
)。这些文件提供了一个如何编写 Deno 程序以及如何为其编写测试的基本示例。main.ts
文件导出一个将两个数字相加的 add
函数,而 main_test.ts
文件则包含该函数的测试。
您还可以为 deno init
指定一个参数,以在特定目录中初始化项目
$ deno init my_deno_project
✅ Project initialized
Run these commands to get started
cd my_deno_project
deno run main.ts
deno test
我们很乐意在此 GitHub Issue 中听取您对该功能的反馈。
实验性 npm 支持
此版本添加了对 npm 描述符的实验性支持。需要强调的是,此功能仍在开发中。npm 描述符非常新,您可能会遇到一些不工作的情况。请将这些问题报告给问题追踪器。我们将在接下来的几个版本中努力改进兼容层和用户体验。
它们的工作方式最好通过一个示例来描述
// main.ts
import express from "npm:express";
const app = express();
app.get("/", function (req, res) {
res.send("Hello World");
});
app.listen(3000);
console.log("listening on http://localhost:3000/");
这些 npm 描述符具有以下格式
npm:<package-name>[@<version-requirement>][/<sub-path>]
然后执行以下操作将启动一个简单的 Express 服务器
$ deno run --unstable --A main.ts
listening on http://localhost:3000/
执行此操作时,无需 npm install
,也不会创建 node_modules
文件夹。这些包也受 Deno 应用程序相同的权限约束。不过目前,会请求一些不必要的权限,但未来上述程序将只要求网络权限。
这些描述符目前可与 deno run
、deno test
和 deno bench
一起使用。类型检查尚不支持。与语言服务器、deno vendor
、deno info
和 deno install
的集成也尚未准备就绪。
npm 包二进制文件可以使用以下格式的描述符从命令行执行,无需 npm 安装
npm:<package-name>[@<version-requirement>][/<binary-name>]
例如
$ deno run --unstable --allow-env --allow-read npm:cowsay@1.5.0 Hello there!
______________
< Hello there! >
--------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
$ deno run --unstable --allow-env --allow-read npm:cowsay@1.5.0/cowthink What to eat?
______________
( What to eat? )
--------------
o ^__^
o (oo)\_______
(__)\ )\/\
||----w |
|| ||
与之前的示例类似,此 npm 包需要环境和读取权限,但未来它不应该需要任何权限。
我们将在未来的版本中为 npm 包二进制文件添加 deno install
和锁文件支持。
由于此功能仍处于实验阶段,导入 npm 描述符时需要指定 --unstable
。
新的实验性 HTTP 服务器 API
Deno 1.25 引入了一个新的实验性 HTTP 服务器,旨在提供同类最佳的 HTTP 性能。我们的基准测试显示,与 Node.js 相比,hello-world 每秒请求性能提高了 4 倍,与我们现有的 Web 服务器相比,性能提高了 3 倍。新服务器甚至比规范的 Rust HTTP 服务器 Hyper 的单线程配置快 20%。
新的 Deno.serve()
API 对我们现有 std/http
服务器的用户来说会非常熟悉,因为它可以作为 std/http
的 serve()
函数的直接替代品。
一个基本的 hello world 服务器现在变得如此简单
Deno.serve(() => new Response("Hello, world!"));
您可以在 doc.deno.land 上找到此 API 的完整文档。
在此示例中,每个请求都通过动态渲染的 React 组件进行响应
// ssr.jsx
import * as React from "npm:react";
import { renderToReadableStream } from "npm:react-dom/server";
const App = () => (
<html>
<body>
<h1>Hello World</h1>
</body>
</html>
);
const options = {
headers: {
"Content-Type": "text/html",
},
};
Deno.serve(
{ port: 4500 },
async () => new Response(await renderToReadableStream(<App />), options),
);
新服务器目前仅支持 HTTP/1.1。无缝的 HTTP/2 支持正在计划中,并将在未来版本中添加。我们现有服务器中的其他功能——例如自动响应体压缩——也正在计划中。
此新服务器目前不应用于生产流量,但我们鼓励您尝试并对其进行基准测试。由于该 API 仍处于实验阶段,因此需要使用 --unstable
标志才能使用它。请将您发现的任何错误报告到 Deno 的问题追踪器。
在未来几周内,您可以期待一篇更详细的博客文章,内容将包含新 HTTP 服务器的性能以及更详尽的基准测试和运行时比较。
启动时间优化
当 Deno 启动时,它会提前分析依赖项以确保远程模块被缓存。这种依赖项分析对于大型文件来说可能相当耗时,因此在 Deno 1.25 中,它会按文件在后台进行缓存。有了这项改进,如果您的任何依赖项在首次运行后有大型文件,您应该会注意到启动时间有显著改善。
例如,ts_morph 依赖于 TypeScript 编译器,后者以一个 10MB 的 JavaScript 文件形式发布。
import { Project } from "https://deno.land/x/ts_morph@15.1.0/mod.ts";
console.log(Project);
在 Deno 的先前版本中,上述代码在我们的一台机器上每次运行大约需要 1080 毫秒。现在,在首次运行后大约只需 225 毫秒。
此外,基线内存使用量的回归问题已得到修复,并且对内存使用量进行了额外改进。您应该会看到与最近版本相比显著的减少。
FFI API 改进
此版本为不稳定的外部函数接口 (Foreign Function Interface) 增加了新功能和性能改进
Uint8Array
和 64 位数字
快速 FFI 调用中的 在 Deno v1.24 中,添加了快速 FFI 调用,显著提高了性能。该优化仅对数字类型启用。
此版本为 u64
、i64
、pointer
和 buffer
类型启用了此快速路径。现在,许多 FFI 模块可以在 JavaScript 中实现接近原生的性能。
使用 Deno FFI 通过 SQLite C API 进行基准测试。越高越好。
buffer
类型
新的 此前,pointer
类型包含将 JS TypedArray
作为参数传递的功能。
此版本添加了一个新类型 buffer
,以利用 TypedArray 的性能优化。
const { symbols: { hash } } = Deno.dlopen("libtest.so", {
hash: {
parameters: ["buffer", "u32"],
result: "u32",
},
});
const u8 = new Uint8Array([1, 2, 3]);
hash(u8, u8.byteLength);
返回 buffer
类型与返回 pointer
类型相同。pointer
类型不再在慢速调用路径中接受 TypedArray
,以鼓励使用此新类型。
之前
cpu: Apple M1
runtime: deno 1.24.0 (aarch64-apple-darwin)
file:///deno/test_ffi/tests/bench.js
hash() 180.77 ns/iter (176.22 ns … 195.53 ns) 181.3 ns 193.97 ns 195.35 ns
之后
cpu: Apple M1
runtime: deno 1.25.0 (aarch64-apple-darwin)
file:///deno/test_ffi/tests/bench.js
hash() 56.01 ns/iter (55.43 ns … 62.43 ns) 56.03 ns 60.02 ns 61.33 ns
Deno.UnsafePointerView
API 更新
Deno.UnsafePointerView
接口新增了三个静态方法
Deno.UnsafePointerView#getCString
Deno.UnsafePointerView#getArrayBuffer
Deno.UnsafePointerView#copyInto
const ptr = symbols.get_hello();
// Read the C String into a JS string.
const string = Deno.UnsafePointerView.getCString(ptr);
// Zero-copy AB to the pointer.
const arrayBuffer = Deno.UnsafePointerView.getArrayBuffer(ptr);
// Copying buffer
const copy = new Uint8Array(32);
Deno.UnsafePointerView.copyInto(ptr, copy);