跳至主要内容
Deno 2 终于来了 🎉️
了解更多

Deno 1.15 版本说明

Deno 1.15 已标记并发布,其中包含以下功能和更改

如果您已经安装了 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。这些函数调用将在专用阻塞线程上运行,并返回一个解析为所需 resultPromise

使用 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ögreenDivy 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 包装以模拟现有的测试框架,如 mochanode-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 测试中使用 chaisinon 进行断言

请注意,此 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 版本对这个兼容性层进行了重大更新,包括添加了一些高度需要的模块(dnshttpnet),以及对 crypto 模块的许多更新。