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 改进
FFI 在 Deno 1.13 中添加,此 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 个不同的 API,它们都处理 TLS:Deno.connectTls
用于建立出站 TLS 连接、Deno.startTls
用于将现有连接升级到 TLS 以及 Deno.createHttpClient
用于更改出站 HTTP 请求的 HTTP 和 TLS 设置。
这三个 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 非常通用,因此可以由 polyfill 包装以模拟现有的测试框架,如 mocha
或 node-tap
。原始说明 为此新 API 做了更详细的说明。
以下是一个使用新 API 的测试示例。它创建了一个数据库连接,对它运行了一些查询作为子测试,然后关闭连接。
Deno.test("database test", async (t) => {
const db = await Database.connect("postgres://127.0.0.1/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://127.0.0.1/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/[email protected]/testing/chai_example.ts
- https://deno.land/[email protected]/testing/sinon_example.ts
请注意,此 API 仍处于实验阶段,将来可能会发生变化。非常欢迎您对这个 API 的反馈!
API 稳定性
1.15 带来了多个 Deno API 的稳定性
Deno.kill
Deno.Process.kill
Deno.resolveDns
使用这些 API 不再需要在 CLI 上传递 --unstable
标志。
我们计划在即将发布的版本中稳定 Deno.signal()
API。
与 Chromium 同步稳定 URLPattern
API
上一个版本介绍了一个用于将 URL 与模式匹配的新不稳定 Web 平台 API。URLPattern
是流行的 path-to-regexp
库的内置替代方案。
模式语法与 path-to-regexp
非常相似。URLPattern
的独特之处在于它能够匹配的不仅仅是路径——它可以单独匹配 URL 的每个部分(协议、主机名、路径名、查询字符串、哈希等)。
此版本与 Chromium 同步稳定了此 API。它将在今天在 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
模块的许多更新。