跳到主要内容
Deno 2.4 现已发布,包含 deno bundle、字节/文本导入、OTel 稳定版等功能
了解更多

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 改进

Deno 1.13 中新增了 FFI,此 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 种处理 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 进行封装,以模拟现有的测试框架,如 mochanode-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 测试中使用 chaisinon 进行断言

请注意,此 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 的发布为该兼容层带来了重大更新,包括增加了备受期待的模块(dnshttpnet),以及对 crypto 模块的多次更新。