Deno 1.15 发布说明
Deno 1.15 已标记并发布,包含以下功能和变更
- 新的加密 API
- FFI 改进
deno uninstall
子命令deno lint --watch
- 内存中的 CA 证书
- 嵌套测试 API
- API 稳定化
- V8 9.5 更新
- 改进 Node 兼容性
如果您已安装 Deno,可以通过运行以下命令升级到 1.15
deno upgrade
如果您是首次安装 Deno,可以使用下面列出的方法之一
# Using Shell (macOS and Linux):
curl -fsSL https://deno.land/x/install/install.sh | sh
# Using PowerShell (Windows):
iwr https://deno.land/x/install/install.ps1 -useb | iex
# Using Homebrew (macOS):
brew install deno
# Using Scoop (Windows):
scoop install deno
# Using Chocolatey (Windows):
choco install deno
新的加密 API
为了在今年年底前实现功能完善的 Web Crypto API 目标,我们在本次发布中取得了良好进展
crypto.subtle.exportKey()
:- RSA 密钥现在可以导出为 spki 格式。
crypto.subtle.importKey()
:- ECDSA 密钥现在可以导入为原始格式。
crypto.subtle.deriveBits()
:- 现在支持 ECDH 派生(仅适用于 P256 密钥)。
crypto.subtle.wrapKey()
:- 现在支持
crypto.subtle.exportKey()
支持的所有密钥和格式组合的密钥封装。
- 现在支持
crypto.subtle.encrypt()
:- 现在支持 AES-CBC 加密。
crypto.subtle.decrypt()
:- 现在支持 AES-CBC 解密。
您可以订阅此 跟踪议题 以获取 Web Crypto API 的进一步进展通知。
感谢 Divy Srivastava 在 Deno 的 Web Crypto 实现方面所做的重要工作。
FFI 改进
Deno 1.13 中新增了 FFI,此 API 允许用户调用以支持 C ABI 的语言(如 C、C++、C#、Kotlin、Nim、Rust 或 Zig)编写的库。
此版本为 FFI API 添加了两个非常有用的功能支持:非阻塞调用和缓冲区参数。
非阻塞调用
在许多用例中,用户可能希望在后台运行 CPU 密集型 FFI 函数,而不会阻塞主线程上的其他任务。
在此版本中,符号可以在 Deno.dlopen
中被标记为 nonblocking
。这些函数调用将在专用阻塞线程上运行,并返回一个解析为所需 result
的 Promise
。
使用 Deno 执行耗时 FFI 调用的示例
// sleep.c
#ifdef _WIN32
#include <Windows.h>
#else
#include <time.h>
#endif
int sleep(unsigned int ms) {
#ifdef _WIN32
Sleep(ms);
#else
struct timespec ts;
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000;
nanosleep(&ts, NULL);
#endif
}
从 Deno 调用
// nonblocking_ffi.ts
const library = Deno.dlopen("./sleep.so", {
sleep: {
parameters: ["usize"],
result: "void",
nonblocking: true,
},
});
library.symbols.sleep(500).then(() => console.log("After"));
console.log("Before");
结果
$ deno run --allow-ffi --unstable nonblocking_ffi.ts
Before
After
缓冲区参数
在 1.15 之前,FFI 符号的参数仅限于基本类型,但此版本增加了对使用缓冲区作为 FFI 调用参数的支持。
当使用缓冲区调用 FFI 符号时,下一个参数必须是缓冲区的长度。
示例
// print_buffer.rs
#[no_mangle]
pub extern "C" fn print_buffer(ptr: *const u8, len: usize) {
let buf = unsafe { std::slice::from_raw_parts(ptr, len) };
println!("{:?}", buf);
}
从 Deno 调用
// print_buffer.ts
const library = Deno.dlopen("./print_buffer.so", {
print_buffer: {
parameters: ["buffer", "usize"],
result: "void",
},
});
const buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
dylib.symbols.print_buffer(buffer, buffer.length);
结果
$ deno run --allow-ffi --unstable print_buffer.ts
[1, 2, 3, 4, 5, 6, 7, 8]
除了传递缓冲区作为参数外,我们认识到能够使用缓冲区作为返回值的重要性,并计划在未来版本中支持此功能。
有关 FFI API 的更多信息,请访问 手册页。
感谢 Elias Sjögreen 和 Divy Srivastava 实现了这些功能。
deno uninstall
命令
此版本引入了 deno uninstall
子命令。它允许您删除先前使用 deno install
安装的命令。
$ deno install
Check https://deno.land/std/examples/welcome.ts
✅ Successfully installed welcome
/Users/lucacasonato/.deno/bin/welcome
$ welcome
Welcome to Deno!
$ deno uninstall welcome
deleted /Users/lucacasonato/.deno/bin/welcome
✅ Successfully uninstalled welcome
以前,通过直接从 .deno/bin
目录中删除命令文件,就已经可以卸载命令了。
deno lint --watch
deno lint
现在支持 --watch
标志,它将在打印诊断信息后保持进程活动,并监视文件更改以更新来自已更改文件的诊断信息。
与其他支持 --watch
标志的子命令一样,Deno 会自动发现需要监视的文件。
感谢 @CGQAQ
贡献了此功能。
内存中的 CA 证书
在过去一年中,Deno 积累了 3 种处理 TLS 的不同 API:用于建立出站 TLS 连接的 Deno.connectTls
,用于将现有连接升级到 TLS 的 Deno.startTls
,以及用于更改出站 HTTP 请求的 HTTP 和 TLS 设置的 Deno.createHttpClient
。
这三个 API 以前都有各种指定自定义 CA 证书的方式。现在这些方式已统一。所有三个 API 现在都接受 caCerts
选项。此属性必须以字符串数组的形式提供,其中每个字符串都是 PEM 编码的 X.509 证书。此数组中可以指定多个证书。
示例:
const caCert = await Deno.readTextFile("./custom_ca_cert.pem");
const client = Deno.connectTls({
hostname: "database.internal",
port: 4443,
caCerts: [caCert],
});
此版本还从 Deno.createHttpClient
中移除了不稳定的 caData
选项,因为新的 API 取代了它。
嵌套测试 API
此版本为 Deno 测试框架添加了一个新的实验性子步骤 API。此新增功能允许用户为 Deno.test
定义的测试定义子步骤。这些子步骤拥有自己的 清理器作用域 并在测试运行器中以缩进形式呈现。新 API 足够通用,可以通过 polyfills 进行封装,以模拟现有的测试框架,如 mocha
或 node-tap
。此新 API 的 原始说明文档 更详细地解释了它。
这是一个使用新 API 的测试示例。它创建一个数据库连接,在子测试中对其运行一些查询,然后关闭连接。
Deno.test("database test", async (t) => {
const db = await Database.connect("postgres://localhost/test");
await t.step("insert user", async () => {
const users = await db.query(
"INSERT INTO users (name) VALUES ('Deno') RETURNING *",
);
assertEquals(users.length, 1);
assertEquals(users[0].name, "Deno");
});
await t.step("insert book", async () => {
const books = await db.query(
"INSERT INTO books (name) VALUES ('The Deno Manual') RETURNING *",
);
assertEquals(books.length, 1);
assertEquals(books[0].name, "The Deno Manual");
});
db.close();
});
用 Mocha 风格编写的相同测试将如下所示:
describe("database test", () => {
let db: Database;
beforeAll(async () => {
db = await Database.connect("postgres://localhost/test");
});
it("insert user", async () => {
const users = await db!.query(
"INSERT INTO users (name) VALUES ('Deno') RETURNING *",
);
assertEquals(users.length, 1);
assertEquals(users[0].name, "Deno");
});
it("insert book", async () => {
const books = await db!.query(
"INSERT INTO books (name) VALUES ('The Deno Manual') RETURNING *",
);
assertEquals(books.length, 1);
assertEquals(books[0].name, "The Deno Manual");
});
afterAll(() => {
db!.close();
});
});
对于更熟悉这种风格的用户,我们为 Mocha 编写了一个简单的 polyfill,它基于这个新 API:https://gist.github.com/lucacasonato/54c03bb267074aaa9b32415dbfb25522。
与此 polyfill 一致,我们现在提供了一些示例,展示如何在 Deno 测试中使用 chai
或 sinon
进行断言
- https://deno.land/std@0.111.0/testing/chai_example.ts
- https://deno.land/std@0.111.0/testing/sinon_example.ts
请注意,此 API 仍处于实验阶段,未来可能会有变动。非常欢迎对该 API 提供反馈!
API 稳定化
1.15 版本带来了多个 Deno API 的稳定化
Deno.kill
Deno.Process.kill
Deno.resolveDns
使用这些 API 不再需要在 CLI 上传递 --unstable
标志。
我们计划在即将发布的版本中稳定 Deno.signal()
API。
URLPattern
API 与 Chromium 同步稳定
上一个版本引入了一个新的不稳定的 Web 平台 API,用于根据模式匹配 URL。URLPattern
是流行的 path-to-regexp
库的内置替代品。
模式语法与 path-to-regexp
非常相似。URLPattern
的不同之处在于,它不仅能够匹配路径,还可以单独匹配 URL 的每个部分(协议、主机名、路径名、查询字符串、哈希等)。
此版本将此 API 与 Chromium 同步并稳定。它将于今天在 Deno 1.15 中可用,并于 10 月 19 日在 Google Chrome 和 Microsoft Edge 的 95 版本中可用。
文档和示例可在 MDN 上找到:https://mdn.org.cn/en-US/docs/Web/API/URLPattern。
V8 9.5 更新
Deno 1.15 包含了 V8 9.5。此版本引入了新的“Intl.DisplayNames v2”JavaScript API、Intl.DateTimeFormat
的扩展 timeZoneName
选项,以及对“WebAssembly 异常处理 (Wasm EH) 提案”的支持。
有关每个变更的详细信息,请参见 V8 9.5 发布说明。
改进 Node 兼容性
为了更容易在 Deno 中运行 Node 程序,新增了一个 --compat
标志(此标志需要 --unstable
)。当此标志存在时,Deno 将自动设置 Node 全局变量(如 process
)并提供 Node 中所有内置模块。这意味着 Deno 现在可以处理如下代码:
import { readFileSync } from "fs";
let passwd = readFileSync("/etc/passwd", "utf-8");
console.log(passwd);
console.log(process.pid);
此版本只是 --compat
的初步实现。我们将在未来的版本中投入大量工作来改进兼容模式,以实现 Node 模拟。
std/node
是一个模块,它为 Node API 提供了兼容层,使得在 Deno 中运行部分 Node 程序成为可能。std 0.111.0 的发布为该兼容层带来了重大更新,包括增加了备受期待的模块(dns
、http
和 net
),以及对 crypto
模块的多次更新。