|
| 1 | +# 译《Deno v1.9 发布说明》 |
| 2 | + |
| 3 | +> - 原文地址:[Deno 1.9 Release Notes](https://deno.com/blog/v1.9) |
| 4 | +> - 原文作者:Bartek Iwańczuk, Luca Casonato, Ryan Dahl, Aaron O'Mullan |
| 5 | +> - 译者:[@hylerrix](https://github.com/hylerrix) |
| 6 | +> - 原文发布时间/翻译时间:20210413/20210430 |
| 7 | +> - 本文属于《[Deno 钻研之术](https://github.com/hylerrix/deno-tutorial)》系列。 |
| 8 | +
|
| 9 | +今天我们发布了 Deno v1.9.0。此版本包含了许多新功能、性能优化以及 Bug 修复: |
| 10 | + |
| 11 | +- **原生 HTTP/2 Web 服务器**:Deno 下的一个快速、准确、功能完整的 HTTP 服务器。 |
| 12 | +- **使用 serde_v8 更快地调用 Rust**:将我们的 op 基准开销优化了 98%。 |
| 13 | +- **Blob URL 支持与 **`**fetch**`** 改进**:新的 Web 兼容性功能。 |
| 14 | +- **LSP 中 import 的支持更完整**:本地、远程和注册表的支持现可以再次使用。 |
| 15 | +- **交互式权限提示框**:以交互式提示框来请求权限而无须预先声明。 |
| 16 | + |
| 17 | +如果你已经安装了 Deno,可以通过 `deno upgrade` 命令来更新到 1.9 版本。如果你是第一次体验 Deno,你可以尝试使用如下命令之一: |
| 18 | + |
| 19 | +```bash |
| 20 | +# Using Shell (macOS and Linux): |
| 21 | +curl -fsSL https://deno.land/x/install/install.sh | sh |
| 22 | + |
| 23 | +# Using PowerShell (Windows): |
| 24 | +iwr https://deno.land/x/install/install.ps1 -useb | iex |
| 25 | + |
| 26 | +# Using Homebrew (macOS): |
| 27 | +brew install deno |
| 28 | + |
| 29 | +# Using Scoop (Windows): |
| 30 | +scoop install deno |
| 31 | + |
| 32 | +# Using Chocolatey (Windows): |
| 33 | +choco install deno |
| 34 | +``` |
| 35 | + |
| 36 | +## 原生 HTTP/2 Web 服务器 |
| 37 | + |
| 38 | +目前 Deno 下的 HTTP 服务器 [std/http](https://deno.land/std/http),是在 TCP 套接字顶部用纯 TypeScript 实现。尽管用了脚本化的 HTTP 服务器,但其依然具有良好的尾部延迟。但是 std/http 的主要缺点在于,它仅仅是 HTTP/1.1,没有提供通向 HTTP/2 的便捷方法。 |
| 39 | + |
| 40 | +最终,我们不想忙于编写 HTTP 服务器的工作。HTTP 变得越来越重要,并且在底层代码里已经存在了良好实现的 HTTP 服务器。 |
| 41 | + |
| 42 | +因此,我们使用 [Hyper](https://hyper.rs/) 来在 Deno 中构建新的原生 HTTP/2 服务器 API。 |
| 43 | + |
| 44 | +与纯 TypeScript 编写的 HTTP 服务器 std/http 相比,该绑定将 http-world 的吞吐量提高了 48%。 |
| 45 | + |
| 46 | + |
| 47 | +我们希望尽快稳定这个新的 API,但是现在你必须使用 `--unstable` 标志。欢迎进行测试并给我们提供反馈。 |
| 48 | + |
| 49 | +```typescript |
| 50 | +const body = new TextEncoder().encode("Hello World"); |
| 51 | +for await (const conn of Deno.listen({ port: 4500 })) { |
| 52 | + (async () => { |
| 53 | + for await (const { respondWith } of Deno.serveHttp(conn)) { |
| 54 | + respondWith(new Response(body)); |
| 55 | + } |
| 56 | + })(); |
| 57 | +} |
| 58 | +``` |
| 59 | + |
| 60 | +我们已经很谨慎地使用与 **fetch()** API 相同的 **Request** 和 **Response** 对象。Rust 和 Response 对象都具有流体(streamable bodies),允许与客户端进行全双工通信。 |
| 61 | + |
| 62 | +另请参考下文关于 ALPN 的部分,这是通过 TLS 发布 HTTP/2 所必需的。 |
| 63 | + |
| 64 | +## 使用 serde_v8 更快地调用 Rust |
| 65 | + |
| 66 | +我们已经将绑定基础设施重建得更加简单和快捷:我们从核心中删除了 1500 多行代码,将基线绑定(又称为 ops 或 opcall)的开销提高了约 65 倍或 -98%,并且建立了干净的 op 基础,可以为我们的发展提供良好的基础(比如用于插件和未来的优化等)。 |
| 67 | + |
| 68 | +在 Deno 的早期版本中,opcalls 遵循请求/响应模式,在 ArrayBuffer 的自定义“有效负载”中对其数据进行编码。此前,这些有效负载使用范围从 JSON、flatbuffers 到自定义二进制编码的各种编码...这不仅成为性能瓶颈,也成为复杂性和碎片化的重要起源。 |
| 69 | + |
| 70 | +[@AaronO](https://github.com/AaronO) 建议,与其在这些二进制格式(JS 和 Rust)之间来回序列化,[不如直接更有效率地](https://github.com/denoland/deno/issues/9540)在 v8 和 Rust 值之间进行序列化。在此建议和一个快速的原型设计下,[serde_v8](https://github.com/denoland/deno/tree/main/serde_v8) 诞生。`serde_v8` 旨在在 v8 和 Rust 之间提供“最大效率”或“零开销”的双射,同时保持表达性和准确性(因为它建立在 David Tolnay 奇妙的 [serde](https://github.com/serde-rs/serde) 库之上)。 |
| 71 | + |
| 72 | +基线 op 开销是衡量给定类 opcall 的最小开销 (单位为每个调用的纳秒) 的一个重要基准。 |
| 73 | + |
| 74 | + |
| 75 | + |
| 76 | +这些 op-layer 的改进不仅仅是学术上的,还大大提升了 Deno 的效率,也提高了我们在 [HTTP 基准测试](https://deno.com/blog/v1.9#http-benches)的吞吐量和延迟。你可以在你自己的 Deno 程序中看到在重负荷下或者是以前遇到的 opcall 效率瓶颈时的改进。 |
| 77 | + |
| 78 | + |
| 79 | + |
| 80 | +如上所见,Deno 中很多常用的功能现在都可以快 ~3 倍地运行。 |
| 81 | + |
| 82 | +## 支持 Blob URL 与改进 `fetch` |
| 83 | + |
| 84 | +此版本下,我们引入了 `blob:`(又称 object URLs)——一个与浏览器中相同的,可以用来创建和撤销 blob URL 的 API: |
| 85 | + |
| 86 | +```typescript |
| 87 | +const blob = new Blob(["Hello World!"]); |
| 88 | +const url = URL.createObjectURL(blob); |
| 89 | +console.log(url); // blob:null/7b09af21-03d5-461e-90a3-af329667d0ac |
| 90 | + |
| 91 | +const resp = await fetch(url); |
| 92 | +console.log(await resp.text()); // Hello World! |
| 93 | + |
| 94 | +URL.revokeObjectURL(url); |
| 95 | +``` |
| 96 | + |
| 97 | +Blob URLs 可用于 `fetch`,使用 `new Worker` 来实例化 Web Worker,以及动态导入(使用`import()`)。 |
| 98 | + |
| 99 | +除了 blob URLS,`fetch` 现在还支持 `data` URLs: |
| 100 | + |
| 101 | +```typescript |
| 102 | +const resp = await fetch("data:text/plain;base64,SGVsbG8gV29ybGQh"); |
| 103 | +console.log(await resp.text()); // Hello World! |
| 104 | +``` |
| 105 | + |
| 106 | +## LSP 中 import 的支持更完整 |
| 107 | + |
| 108 | +此版本中,还为 Deno Language Server(一个为 Deno 提供编辑器拓展功能的工具)添加了一些很棒的新功能和改进。 |
| 109 | + |
| 110 | +首先,我们从旧的 VS Code 拓展中改进并重新引入了导入补全功能。它允许用户在 import 语句中获得补全。LSP 提供本地文件的补全、已经下载到 DENO——DIR 缓存的文件以及注册表的补全。 |
| 111 | + |
| 112 | +这是功能的示例: |
| 113 | + |
| 114 | + |
| 115 | + |
| 116 | +想要开启 [https://deno.land/x](https://deno.land/x) 仓库的补全功能,需要在你的 VS Code(或其它编辑器) 中添加如下配置: |
| 117 | + |
| 118 | +```typescript |
| 119 | +{ |
| 120 | + "deno": { |
| 121 | + "suggest": { |
| 122 | + "imports": { |
| 123 | + "hosts": { |
| 124 | + "https://deno.land": true |
| 125 | + } |
| 126 | + } |
| 127 | + } |
| 128 | + } |
| 129 | +} |
| 130 | +``` |
| 131 | + |
| 132 | +注册表自动补全功能目前由 [https://deno.land/x](https://deno.land/x) 提供。我们希望更多的其它注册表会根据注册表协议来支持这个功能。[Skypack](https://skypack.dev/) 注册表显示出了相关兴趣,并且可能很快会得到支持。如果要添加对自己注册表的支持,则可以阅读[注册表实现文档](https://github.com/denoland/vscode_deno/blob/main/docs/ImportCompletions.md#module-registry-completions)。 |
| 133 | + |
| 134 | +除了新的导入补全功能之外,我们还实现了 `textDocument/foldingRange` 和 `textDocument/selectionRange` 的 LSP 函数,使你的编辑器可以再选择期间提供更好地文本捕捉,并更好地支持折叠和拓展代码块。 |
| 135 | + |
| 136 | +此版本还包含许多针对 LSP 的错误修复,其中一个特殊的缺陷是 Windows 系统上的一个讨厌的错误:当 LSP 遇到特定的 `file://` URL时,会导致 LSP 崩溃。 |
| 137 | + |
| 138 | +## `--allow-env` 和 `--allow-run` 的白名单 |
| 139 | + |
| 140 | +Deno 的多个权限标志接收一个允许列表,使得程序权限可以再细粒度地得到控制。例如,使用 `--allow-read=/tmp` 仅授予对 `/tmp` 目录的读取权限。 |
| 141 | + |
| 142 | +在 1.9 之前的版本中,`--allow-env` 和 `--allow-run` 都是全部开启或全部关闭,这意味着通过这些标志将授予对环境变量的完全访问权限,并且可以分别为系统中的任何二进制文件生成子进程。 |
| 143 | + |
| 144 | +现在可以精确地指定程序应该访问哪些环境变量,或者允许程序产生哪些子进程: |
| 145 | + |
| 146 | +```bash |
| 147 | +$ deno run --allow-env=DEBUG,LOG https://deno.com/v1.9/env_permissions.ts |
| 148 | +$ deno run --allow-run=deno https://deno.com/v1.9/run_permissions.ts |
| 149 | +``` |
| 150 | + |
| 151 | +此外,`Deno.permissions.query()` 现在允许使用命令字段查询执行特定二进制文件的权限: |
| 152 | + |
| 153 | +```typescript |
| 154 | +await Deno.permissions.query({ name: "run", command: "deno" }); |
| 155 | +``` |
| 156 | + |
| 157 | +## 交互式权限提示框 |
| 158 | + |
| 159 | +当前在 Deno 中,如果你运行的程序确实相应的权限标志,它将抛出错误并退出。在 1.9 中,我们添加了 --pormpt 标志,允许用户迭代地授予运行时所需的权限。 |
| 160 | + |
| 161 | +当从 Internet 运行一次性脚本时,使用 --prompt 尤其有用:你无需预先知道所有必需的权限,而是可以在没有任何权限的情况下运行脚本,并根据程序的请求逐一授予或拒绝。 |
| 162 | + |
| 163 | + |
| 164 | + |
| 165 | +尝试运行这个示例:`deno run --prompt ``[https://deno.com/v1.9/prompt_permissions.ts](https://deno.com/v1.9/prompt_permissions.ts)`。 |
| 166 | + |
| 167 | +如果 --prompt 对你有用,请告诉我们,我们正在考虑在将来的版本中默认将其打开。 |
| 168 | + |
| 169 | +## `Deno.listenTls` 中的 ALPN 支持 |
| 170 | + |
| 171 | +HTTP/2 协议与连接无关。因此,它可以用于 Unix 套接字、TCP 套接字或者使用 TLS 的连接。主流浏览器只允许在 TLS 握手过程中宣布支持 HTTP/2 的 TLS 连接。它通过“应用层协议协商”TLS 扩展来实现,也被称为 ALPN。这种对 TLS 握手的扩展允许 TLS 服务器和客户端就它们将使用哪种应用协议来进行 TLS 连接通信进行协商。HTTP/1.1 和 HTTP/2 是网络上两个主要的应用协议。这些协议的 ALPN 名称分别为“http/1.1”和“h2”。浏览器只会将 HTTP/ 2 请求发送到声明支持 HTTP/2 的服务器。如果没有列出 ALPN 协议,或者在 ALPN 协议中只列出了“http/1.1”,则将使用 HTTP/1.1。 |
| 172 | + |
| 173 | +迄今为止,`std/http` 服务器仅支持 HTTP/1.1,因此无需支持 TLS 连接上的 ALPN。当`Deno.serviceHttp` 在这一版本中引入时,事情发生了变化。要在 Deno 中实现完全的 HTTP/2,我们现在添加了对指定 ALPN 协议的支持,当 TLS 侦听器通过 `Deno.ListentLs` 启动时,它将进行公告。 |
| 174 | + |
| 175 | +下面是一个创建完全支持 HTTP/2 的 HTTPS 服务器的例子: |
| 176 | + |
| 177 | +```typescript |
| 178 | +const listener = Deno.listenTls({ |
| 179 | + port: 443, |
| 180 | + certFile: "./cert.pem", |
| 181 | + keyFile: "./key.pem", |
| 182 | + alpnProtocols: ["h2", "http/1.1"], |
| 183 | +}); |
| 184 | + |
| 185 | +for await (const conn of listener) { |
| 186 | + handleConn(conn); |
| 187 | +} |
| 188 | + |
| 189 | +async function handleConn(conn: Deno.Conn) { |
| 190 | + const httpConn = Deno.serveHttp(conn); |
| 191 | + for await (const { request, respondWith } of httpConn) { |
| 192 | + respondWith(new Response(`Responding to ${request.url}`)); |
| 193 | + } |
| 194 | +} |
| 195 | +``` |
| 196 | + |
| 197 | +## 新稳定的 API |
| 198 | + |
| 199 | +1.9 稳定了与文件系统相关的几个 API: |
| 200 | + |
| 201 | +- `Deno.fstat` |
| 202 | +- `Deno.fstatSync` |
| 203 | +- `Deno.ftruncate` |
| 204 | +- `Deno.ftruncateSync` |
| 205 | + |
| 206 | +此外如下方法加入到了 Deno.file 类中: |
| 207 | + |
| 208 | +- `File.stat` |
| 209 | +- `File.statSync` |
| 210 | +- `File.truncate` |
| 211 | +- `File.truncateSync` |
| 212 | + |
| 213 | +## 新弃用的 API |
| 214 | + |
| 215 | +为了使更多使用 Deno 编写的代码直接移植到浏览器和其他非 Deno 运行时中,我们决定弃用并最终从 Deno 命名空间中删除所有不受系统 API 支持的 API。这些 API 将被移植至 Deno 标准库中,该库也可以在浏览器中使用。 |
| 216 | + |
| 217 | +在此版本中,我们不推荐使用以下 API: |
| 218 | + |
| 219 | +- `Deno.Buffer` |
| 220 | +- `Deno.readAll` |
| 221 | +- `Deno.readAllSync` |
| 222 | +- `Deno.writeAll` |
| 223 | +- `Deno.writeAllSync` |
| 224 | +- `Deno.iter` |
| 225 | +- `Deno.iterSync` |
| 226 | + |
| 227 | +这些 API 已移至 `std/io` 模块中。我们在 `deno lint` 中引入了一个新的 lint 规则,它可以发现开发者使用这些不稳定的 API,并发出警告。它还会建议开发者在标准库找到该 API。 |
| 228 | + |
| 229 | +在 Deno 2.0 中,我们计划删除这些废弃的 API。更激进的弃用信息可能会出现在 2.0 之前的版本。请尽可能快地迁移使用到这些弃用 API 的代码。 |
| 230 | + |
| 231 | +## 新的 TypeScript 默认选项 `useDefineForClassFields` |
| 232 | + |
| 233 | +在此发布中,我们修改了默认的 Deno tsconfig,包括 `"useDefineForClassFields": true` 选项。这个选项使 TypeScript 对类字段的处理符合标准 ECMA 脚本语义。此选项不能在用户代码中覆盖。我们希望大部分用户不必更改代码。 |
| 234 | + |
| 235 | +> © [https://github.com/hylerrix/deno-tutorial](https://github.com/hylerrix/deno-tutorial) 2020~2021 |
0 commit comments