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

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

如果您已经安装了 Deno,可以通过运行以下命令升级到 1.23

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

默认情况下不进行类型检查

Deno 始终会在要求执行程序时运行类型检查。但是,评估和类型检查是完全不同的操作,涉及完全不同的编译器,每个编译器都有完全不同的执行速度。评估代码使用 Google 的 V8,而类型检查使用 Microsoft 的 TypeScript 编译器。类型检查非常慢,通常需要几秒钟才能完成。另一方面,V8 启动和评估非常快。

如今,大多数程序员通过 LSP 在他们的编辑器中与类型检查器进行交互。这意味着他们在编程时会不断获得提示和完成。在 deno run 操作中默认插入另一个完整的类型检查步骤没有意义。类型检查更像是一个类似于 linting 的操作,您在 CI 期间执行此操作以确保没有类型错误。

还应强调的是,与类型检查不同,类型剥离是一个快速操作(在源代码大小方面是线性时间)。Deno 将默认进行类型剥离,而不是类型检查。

如果您仍然想要以前的行为(类型检查然后执行),请使用 --check 标志。

我们已经计划了几个月要进行此更改,确保向用户发出警告并引入 --check 标志。查看 v1.22 中的说明.

此更改影响 deno rundeno evaldeno cache。下表描述了各种子命令的类型检查行为。这里“本地”意味着只有来自本地代码的错误才会导致类型错误,从 https URL(远程)导入的模块可能存在未报告的类型错误。(要为所有模块启用类型检查,请使用 --check=all。)

子命令 类型检查模式
deno bench 📁 本地
deno bundle 📁 本地
deno cache ❌ 无
deno check 📁 本地
deno compile 📁 本地
deno eval ❌ 无
deno repl ❌ 无
deno run ❌ 无
deno test 📁 本地

移除不稳定的 Deno.sleepSync API

在此版本中,Deno.sleepSync 已被移除,因为由于此功能已经可以通过现有的 Web API 获得,因此对它没有明确的必要性。此外,它很可能会引起问题:Deno.sleepSync 完全阻塞了事件循环。例如,如果它在 Web 服务器处理程序函数中被调用,服务器将在返回之前停止为请求提供服务。

如果您真的想要此功能,可以通过使用以下函数来实现它

function sleepSync(timeout) {
  const sab = new SharedArrayBuffer(1024);
  const int32 = new Int32Array(sab);
  Atomics.wait(int32, 0, 0, timeout);
}

文件监视器监视动态导入

从 v1.23 开始,内置文件监视器(您可以使用 --watch 标志激活它)还将监视动态导入的文件的更改。

// mod.ts <--- this file was being watched
import foo from "./foo.ts"; // <--- this file was also being watched

console.log(foo);

const bar = await import("./bar.ts"); // <--- this file was not being watched in previous versions;
// starting with v1.23 any changes to `bar.ts` will also cause the process to restart

此功能已允许在 Fresh Web 框架中获得 更好的开发体验

deno task 更新

Deno 包含一个不稳定deno task 子命令,它提供了一种跨平台的方式来定义和执行特定于代码库的自定义命令。此版本包含一些改进。

新的 --cwd <path> 标志

deno task 具有一个属性,默认情况下,它使用 Deno 配置文件(例如 deno.json)的目录作为当前工作目录来执行命令。这允许任务使用相对路径,并且无论您从哪个子目录树中执行 deno task,它都可以继续工作。

虽然这种行为在大多数情况下都是想要的,但在某些情况下它却不是。在这些情况下,您现在可以提供一个 --cwd <path> 标志。

例如,给定一个名为 wasmbuild 的任务,它位于 deno.json 文件中

# use the sub directory project1 as the cwd for the task
deno task --cwd project1 wasmbuild
# use the cwd (project2) as the cwd for the task
cd project2 && deno task --cwd . wasmbuild

任务定义中的重定向

添加了一些重定向支持,以提供一种将 stdout 和/或 stderr 管道到文件的方法。

例如,以下内容将 deno run main.tsstdout 重定向到文件系统上的名为 file.txt 的文件,前提是在 deno 任务中定义并运行 deno task collect

{
  "tasks": {
    "collect": "deno run main.ts > file.txt"
  }
}

要改为重定向 stderr,请使用 2> 而不是 >

deno run main.ts 2> file.txt

要重定向 stdoutstderr,请使用 &>

deno run main.ts &> file.txt

要追加到文件,而不是覆盖现有文件,请使用两个右尖括号而不是一个

deno run main.ts >> file.txt

可以通过重定向到 /dev/null 来抑制命令的 stdout、stderr 或两者。这在跨平台情况下都有效,包括 Windows。

# suppress stdout
deno run main.ts > /dev/null
# suppress stderr
deno run main.ts 2> /dev/null
# suppress both stdout and stderr
deno run main.ts &> /dev/null

请注意,未实现多个重定向,并且目前不支持。

跨平台 catxargs

deno task 具有几个内置的跨平台命令,可以帮助减少冗长。此更新添加了 catxargs 的基本实现,适用于 Linux、Mac 和 Windows。

请注意,并非所有标志都已实现,请向 deno_task_shell 存储库报告任何问题。还要记住,您始终可以通过在 Linux 和 Mac 上(sh -c <command>)通过 sh 来运行本机系统命令,以非跨平台的方式运行它。

deno fmt 更新

deno fmt 现在默认情况下会格式化 .cjs.cts.mjs.mts 文件。

此外,类型中的一些不必要的括号将被自动移除。例如…

type Test = (string | number);

…现在将格式化为…

type Test = string | number;

新的不稳定 Deno.getGid() API

在 v1.23 中,我们添加了一个新的不稳定 API:Deno.getGid()

使用此 API,您可以检索用户组的 ID。请注意,此 API 在 Linux 和 macOS 上有效,但在 Windows 上将返回 null

console.log(Deno.getGid());
// 20

此 API 需要 --allow-env 权限标志。

感谢 James Bradlee 为此功能做出贡献。

deno info 支持 --config--no-config 标志

此版本添加了对 --config--no-config 标志的支持。在之前的版本中,deno info 会自动查找 deno.json 文件,但没有办法手动指定配置文件或完全禁用它。

感谢 Mark Ladyshau 为此功能做出贡献。

在 REPL 中强制换行

此版本对 REPL 做了一些小的改善,提升了用户体验。

现在使用 ctrl + s 组合键可以在 REPL 中编辑代码时强制换行。

感谢 @sigmaSd 为此功能做出贡献。

FFI API 更新

以前,当通过 FFI 调用的函数返回 64 位数字时,会返回普通的 JavaScript 数字。但是,JavaScript 数字只有 53 位整数精度,这意味着有时会得到不正确的结果。通过此更改,将返回 BigInt。此更改还允许将 BigInt 值作为参数传递。

感谢 Elias Sjögreen 为此功能做出贡献。

在 Windows 上监听 SIGINT 和 SIGBREAK 信号的支持

此版本添加了在 Windows 上监听 SIGINT (ctrl+c) 和 SIGBREAK (ctrl+break) 的功能。

Deno.addSignalListener("SIGINT", () => {
  console.log("Received ctrl+c");
});

Deno.addSignalListener("SIGBREAK", () => {
  console.log("Received ctrl+break");
});

手册 中了解有关操作系统信号的更多信息。

对于在 Windows 上支持 Deno.kill SIGINT 和 SIGBREAK,请关注问题 #14866

感谢 Geert-Jan Zwiers@juzi5201314 为此功能做出贡献。

CompressionStreamDecompressionStream 中支持 "deflate-raw"

Deno 现在通过 RFC1951 中指定的 "deflate-raw" 格式字符串支持“DEFLATE 算法”。(不要与 "deflate" 混淆,"deflate" 是“ZLIB 压缩数据格式” RFC1950。)

let input = await Deno.open("README.md");
const compressed = input.readable.pipeThrough(
  new CompressionStream("deflate-raw"),
);
let output = await Deno.open("README.md.zz", { create: true, write: true });
compressed.pipeTo(output.writable);

TypeScript 4.7

Deno v1.23 附带了最新稳定版本的 TypeScript。有关 TypeScript 中新功能的更多信息,请参阅 TypeScript 的 4.7 博客文章

flags 标准模块的更改

std/flags 最初是 minimist 的分支,直到最近才对其进行任何实质性更改。

在此版本中,对 parse 函数有两个重大更改。

collect 选项

collect 选项是一个新选项,用于指定选项参数是否可收集。当您在 collect 选项中指定参数名称时,相同参数的多次出现将被收集到数组中。

import { parse } from "https://deno.land/[email protected]/flags/mod.ts";

console.log(parse(Deno.args, { string: "foo", collect: "foo" }));

执行如下

$ deno run cli.js
{ _: [], foo: [] }
$ deno run cli.js --foo 1
{ _: [], foo: [ "1" ] }
$ deno run cli.js --foo 1 --foo 2
{ _: [], foo: [ "1", "2" ] }
$ deno run cli.js --foo 1 --foo 2 --foo 3
{ _: [], foo: [ "1", "2", "3" ] }

请注意,解析结果中的 foo 始终具有 string[] 类型。

在此更改之前,所有参数都是自动可收集的,并且具有 T | T[] 类型,其中 T 通常是 booleanstring

我们发现这种行为并不合理,因为在大多数情况下,大多数参数都不应该多次指定,但由于这种行为,工具作者总是需要使用 Array.isArray() 检查参数类型。

因此,这种行为变为可选,并且此收集功能仅在 collect 选项中明确指定时才会发生。

要迁移,如果您的 CLI 工具使用数组类型参数,请在 collect 选项中指定参数名称。

negatable 选项

negatable 选项是一个新选项。如果您在 negatable 中指定参数名称,那么 --no-arg 形式的标志将被视为 --arg=false

以下是一个示例

import { parse } from "https://deno.land/[email protected]/flags/mod.ts";
console.log(parse(Deno.args, { boolean: "foo", negatable: "foo" }));

执行如下

$ deno run cli.js
{ _: [], foo: false }
$ deno run cli.js --foo
{ _: [], foo: true }
$ deno run cli.js --no-foo
{ _: [], foo: false }

negatable 也可以与 string 一起使用

import { parse } from "https://deno.land/[email protected]/flags/mod.ts";
console.log(
  parse(Deno.args, {
    string: "foo",
    negatable: "foo",
    default: { foo: "bar" },
  }),
);

执行方式如下

$ deno run cli.js
{ _: [], foo: "bar" }
$ deno run cli.js --foo baz
{ _: [], foo: "baz" }
$ deno run cli.js --no-foo
{ _: [], foo: false }

即使 foo 指定为 string 选项,foo 也会变为 false。这对于删除选项的默认值很有用,如上述示例所示。

在之前的版本中,这种可否定行为默认应用于每个参数,但我们发现这并不合理。因此,它被更改为可选。

要迁移,如果您的 CLI 工具依赖于此 --no-arg 类型参数,请在 negatable 选项中指定参数名称。

感谢 Benjamin Fischer 为此功能做出贡献。

assertThrowsassertRejects 的更改

接受 errorCallback 作为第二个参数的 assertThrows 的签名已弃用。相反,assertThrows 现在将返回抛出的错误值。

如果您使用以下任何断言

import { assertThrows } from "https://deno.land/[email protected]/testing/asserts.ts";

assertThrows(
  () => someFunc(),
  (err) => {
    // some assertions about err
  },
);

请将其更新为以下形式

import { assertThrows } from "https://deno.land/[email protected]/testing/asserts.ts";

const err = assertThrows(
  () => someFunc(),
);

// some assertions about err

此更改背后的动机是 errorCallback 仅接受对抛出值的同步断言。通过此更改,您可以对抛出的值执行任何断言,包括异步操作。

相同的更改也应用于 assertRejects 函数。它返回的 Promise 现在会解析为从内部 Promise 拒绝中检索到的错误。

感谢 Mark Ladyshau 为此功能做出贡献。