Deno 1.16 版本说明
Deno 1.16 已标记并发布,其中包含以下功能和更改
fetch
现在支持获取文件 URL- 支持新的 JSX 转换
- 新的不稳定信号监听器 API
Error.cause
现在在控制台中显示- 握手 TLS 连接现在可以显式完成
- Web 流 API 的改进
Deno.startTls
已稳定- 每个测试权限现在是稳定的
localStorage
不再需要--location
- 支持在中止
AbortSignal
时指定原因 - Deno 到 npm 包构建工具
- WebAssembly 引用类型现在在稳定版中可用
findLast
和findLastIndex
数组方法
如果您已经安装了 Deno,可以通过运行以下命令升级到 1.16
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
新功能和更改
fetch
现在支持获取文件 URL
此版本添加了对使用 fetch
从本地文件系统读取文件的支持。这对于使用 import.meta.url
获取相对于当前模块的文件很有用,就像通常为 WASM 模块所做的那样。
以下是如何读取 /etc/hosts 文件的示例
const resp = await fetch("file:///etc/hosts");
const text = await resp.text();
console.log(text);
注意:上面的示例在 Windows 上不会工作,因为 /etc/hosts 文件在 Windows 上位于不同的位置。请尝试以下代码
const resp = await fetch("file:///C:/Windows/System32/drivers/etc/hosts");
--allow-read
权限是使用 fetch
从本地文件系统读取文件所必需的。
文件的内容以块的形式读取,因此这是一种通过 HTTP 流式传输大型文件的好方法,而不必将整个文件加载到内存中。
import { serve } from "https://deno.land/std/http/server.ts";
serve((_req) => {
const resp = await fetch(new URL("./static/index.html", import.meta.url));
return new Response(resp.body, {
headers: { "content-type": "text/html; charset=utf-8" },
});
});
文件获取的行为在任何 Web 规范中都没有规定,但我们的实现基于 Firefox 中从磁盘读取文件的实现。
- 如果找不到文件,则
fetch
返回的承诺将拒绝,并带有TypeError
。 - 如果指定路径处的项目是目录,则
fetch
返回的承诺将拒绝,并带有TypeError
。 - 响应中没有设置
content-length
标头。这是因为响应主体是流,因此无法提前知道确切的长度。 - 响应中没有设置
content-type
标头。如果您想从文件扩展名推断出内容类型,可以使用media_types
模块,该模块位于 https://deno.land/x 上。
支持新的 JSX 转换
React 17 引入了一个 新的 JSX 转换,该转换对 JSX 转换 API 进行了改进,并允许自动导入 JSX 运行时库。从该版本开始,Deno 支持这些转换。
它可以使用两种不同的方式。第一种方法是在 .jsx
或 .tsx
文件中使用 @jsxImportSource
标记。例如,要从 esm.sh 使用 Preact
/** @jsxImportSource https://esm.sh/preact */
export Welcome({ name }) {
return (
<div>
<h1>Welcome {name}</h1>
</div>
);
}
另一个选项是使用 配置文件 并设置项目范围的编译器选项
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "https://esm.sh/preact"
}
}
然后在命令行上传递 --config
文件(或在您的编辑器中设置 deno.config
选项)。
有关更多详细信息,请参阅有关 配置 JSX 的手册部分。
新的不稳定信号监听器 API
此版本添加了一个用于监听操作系统信号的新不稳定 API。新的 API 目前处于实验阶段,将来可能会发生变化。它取代了现有的 Deno.signals
API(它也是不稳定的)。
const listener = () => {
console.log("SIGTERM!");
};
// Starts listening to SIGTERM
Deno.addSignalListener("SIGTERM", listener);
// Stops listening to SIGTERM
Deno.removeSignalListener("SIGTERM", listener);
我们很期待社区的反馈。如果您有任何建议,请打开一个问题.
Error.cause
现在在控制台中显示
自 Deno 1.13 以来,Error.cause
属性一直被支持,作为一种将原因附加到错误的方式。这对于调试应用程序深处发生的错误很有用,允许开发人员将这些错误包装在有用的信息中,以帮助调试问题。
从该版本开始,当通过 console.log
抛出或记录错误时,我们将在控制台中显示 Error.cause
属性。
> throw new Error("main error", { cause: new TypeError("caused by this") })
Uncaught Error: main error
at <anonymous>:2:7
Caused by TypeError: caused by this
at <anonymous>:3:12
这与 Node.js 17 的行为一致。
感谢 Kenta Moriuchi 实现此功能。
握手 TLS 连接现在可以显式完成
在通过 TLS 建立连接后,在加密连接上可以读取或写入数据之前,需要执行 TLS 握手。大多数用户不需要关心握手的细节,这就是为什么当用户第一次尝试在连接上读取或写入数据时,我们会自动执行握手。
此版本向 Deno.TlsConn
添加了一个 handshake()
方法,可以调用该方法以显式触发握手。此方法返回一个承诺,该承诺在握手完成后解析。如果该方法在握手已完成之后被调用,则该承诺将立即解析。如果该方法在握手正在进行但尚未完成时被调用,则返回的承诺将在握手完成后解析。
Web 流 API 的改进
此版本引入了 Web 流 API 的多个新功能。
ReadableStreamBYOBReader
现在受支持。这些“自带缓冲区”(也称为 BYOB)ReadableStream
阅读器允许读取到开发人员提供的缓冲区中,从而与常规ReadableStreamDefaultReader
相比,最大限度地减少了复制次数。您可以在 MDN 上了解有关此 API 的更多信息。WritableStreamDefaultController.signal
现在受支持。有关更多信息,请参阅 说明。ReadableStream.getIterator
已被删除。此方法自 Deno 1.7 以来一直被弃用,并且从未在任何浏览器中实现。ReadableStream
本身一直都实现了AsyncIterable
协议,因此在迭代流时请改用该协议。
感谢 @crowlKats 对 Web 流实现的工作。
Deno.startTls
已稳定
在 Deno 中,有两种方法可以通过 TLS 连接到服务器:Deno.connectTls
和 Deno.startTls
。第一个用于当您想要打开一个 TCP 连接,然后立即开始在该连接上进行 TLS 通信时。第二个用于当您需要先创建一个纯文本 TCP 连接,交换一些数据,然后开始在该连接上进行 TLS 通信时。
Deno 1.16 版本稳定了Deno.startTls
API。这使得编写稳定 Deno 的 SMTP 驱动程序成为可能。它还允许为稳定 Deno 编写的 Postgres 和 MySQL 驱动程序。现在,Deno 的https://deno.land/x/postgres 驱动程序在 Deno 稳定版中完全可用
import { Client } from "https://deno.land/x/[email protected]/mod.ts";
const client = new Client({
user: "user",
database: "test",
hostname: "psql.example.com",
port: 5432,
tls: {
enforce: true,
caCertificates: [await Deno.readTextFile("/path/to/ca.crt")],
},
});
await client.connect();
const result = await client.queryObject("SELECT id, name FROM people");
console.log(result.rows); // [{id: 1, name: 'Carlos'}, ...]
每个测试的权限现在已经稳定
早在 Deno 1.10 版本中,我们引入了一个功能,允许您为每个测试设置权限。这使得测试您的程序在不同权限设置下的行为变得非常容易。此功能现在已经稳定:它不再需要 --unstable
。例如,请查看上面链接的 1.10 版本博客文章。
请记住,测试用例请求的权限不能超过使用 --allow-*
标志授予进程的权限。如果在权限对象中省略了一个键,则它会从相应的 --allow-*
标志继承它的值。
localStorage
不再需要 --location
在 Deno 的早期版本中,localStorage
API 只能在用户使用 --location
标志启动 Deno 进程时使用。此版本在您在没有 --location
标志的情况下启动 Deno 时,为 localStorage
使用的存储桶添加了一个隐式不透明键。它按如下方式派生
- 使用
--location
标志时,位置的来源用于唯一地存储数据。这意味着http://example.com/a.ts
和http://example.com/b.ts
以及http://example.com:80/
将共享相同的存储空间,但https://example.com/
将不同。 - 如果没有位置说明符,但指定了
--config
配置文件,则使用该配置文件的绝对路径。这意味着deno run --config deno.jsonc a.ts
和deno run --config deno.jsonc b.ts
将共享相同的存储空间,但deno run --config tsconfig.json a.ts
将不同。 - 如果没有配置或位置说明符,Deno 将使用主模块的绝对路径来确定共享哪些存储空间。Deno REPL 生成一个基于
deno
启动位置的当前工作目录的“合成”主模块。这意味着从相同路径多次调用 REPL 将共享持久化的localStorage
数据。
以下是一些示例,有助于阐明这种行为
# You can persist data, even without --location
$ cat one.js
console.log(localStorage.getItem("file"));
localStorage.setItem("file", Deno.mainModule);
$ deno run one.js
null
$ deno run one.js
file:///tmp/one.js
# The key for the storage bucket is derived from the main module, so a module
# cannot read or write data written by a program with a different main module.
$ cat two.js
console.log(localStorage.getItem("file"));
localStorage.setItem("file", Deno.mainModule);
$ deno run two.js
null
$ deno run two.js
file:///tmp/two.js
# The key is derived from the **main module** (the entrypoint), not the module
# that called `localStorage`!
$ cat three.js
import "./two.js";
$ deno run three.js
null
$ deno run three.js
file:///tmp/three.js
# If you have a config file, that is used as the key for the storage bucket.
$ deno run --config=deno.jsonc one.js
null
$ deno run --config=deno.jsonc one.js
file:///tmp/one.js
$ deno run --config=deno.jsonc two.js
file:///tmp/one.js
$ deno run --config=deno.jsonc one.js
file:///tmp/two.js
# You can use --location to specify an explicit origin though, like before. In
# this case, different main modules (entrypoints) can share a single storage
# bucket.
$ deno run --location=https://example.com one.js
null
$ deno run --location=https://example.com one.js
file:///tmp/one.js
$ deno run --location=https://example.com two.js
file:///tmp/one.js
$ deno run --location=https://example.com one.js
file:///tmp/two.js
您可以在手册中找到更多信息:https://docs.deno.org.cn/runtime/manual/runtime/web_storage_api
支持在中止 AbortSignal 时指定原因
WHATWG 最近指定了对在中止 AbortSignal 时指定原因的支持。Deno 是第一个实现此新功能的平台
const abortController = new AbortController();
abortController.abort();
console.log(abortController.signal.reason); // DOMException: The signal has been aborted
const abortController = new AbortController();
const reason = new DOMException("The request timed out", "TimeoutError");
abortController.abort(reason);
console.log(abortController.signal.reason); // DOMException: The request timed out
感谢@crowlKats 实现此功能。
Deno 到 npm 包构建工具
我们继续改进 Node 兼容模式 (--compat
),但在本版本中没有具体内容可宣布。但是,我们发布了一个名为dnt的新系统,用于将用 Deno 编写的模块发布为 npm 包。
默认情况下,dnt 将把您的 Deno 模块转换为规范的 TypeScript,类型检查,构建具有 TypeScript 声明文件的 ESM & CommonJS 混合包,最后在 Node.js 中针对输出运行您的 Deno 测试代码。完成后,您只需将输出目录 npm publish
。
一个已经使用 dnt 的示例项目是deno_license_checker,它现在已发布为 npm 包:https://npmjs.net.cn/package/@kt3k/license-checker
您可以使用以下命令尝试它
npm install -g @kt3k/license-checker
这使您能够在 Node 环境中使用 Deno优先代码。
这还处于早期阶段,但如果您尝试使用它,彻底测试和检查它的输出,并查看出现哪些问题或挑战,我们将不胜感激,以便我们可以优先处理并解决它们。
V8 更新至 9.7 版本
此版本附带 V8 9.7。Deno 1.15 附带 V8 9.5,因此这次您将获得两个 V8 版本的新 JS 好东西 😀
与往常一样,V8 版本还带来了许多性能改进和错误修复。
请查看 V8 的发行说明以了解更多详细信息:https://v8.node.org.cn/blog/v8-release-97.
现在支持 WebAssembly 引用类型
引用类型提案允许在 WebAssembly 模块中不透明地使用来自 JavaScript 的外部引用。externref
(以前称为 anyref
)数据类型提供了一种安全的方法来保存对 JavaScript 对象的引用,并且与 V8 的垃圾收集器完全集成。
此功能在 V8 9.6 中引入。请参阅https://v8.node.org.cn/blog/v8-release-96.
findLast
和 findLastIndex
数组方法
Array
和 TypedArray
上的 findLast
和 findLastIndex
方法从数组的末尾查找与谓词匹配的元素。
例如
[1, 2, 3, 4].findLast((el) => el % 2 === 0);
// → 4 (last even element)
有关更多信息,请参阅功能说明.