[译] Deno 1.0发布

全篇共 14368 字。按500字/分钟阅读,预计用时 28.7 分钟。总访问 60 次,日访问 2 次。

动态语言是有用的工具。脚本编写使用户可以快速简洁地将复杂的系统连接在一起并表达想法,而不必担心诸如内存管理或构建系统之类的细节。近年来,像Rust和Go这样的编程语言使产生复杂的本机代码变得更加容易。这些项目是计算机基础架构中极为重要的发展。但是,我们声称拥有一个能够解决各种问题领域的强大脚本环境仍然很重要。

Dynamic languages are useful tools. Scripting allows users to rapidly and succinctly tie together complex systems and express ideas without worrying about details like memory management or build systems. In recent years programming languages like Rust and Go have made it much easier to produce sophisticated native machine code; these projects are incredibly important developments in computer infrastructure. However, we claim it is still important to have a powerful scripting environment that can address a wide range of problem domains.

JavaScript是使用最广泛的动态语言,可通过Web浏览器在每台设备上运行。大量的程序员精通JavaScript,并且已经在优化其执行方面投入了大量精力。通过像ECMA International这样的标准组织,对语言进行了标准化,不断的改进。我们相信JavaScript是动态语言工具的自然选择;无论是在浏览器环境中还是作为独立进程。

JavaScript is the most widely used dynamic language, operating on every device with a web browser. Vast numbers of programmers are fluent in JavaScript and much effort has been put into optimizing its execution. Through standards organizations like ECMA International, the language has been carefully and continuously improved. We believe JavaScript is the natural choice for dynamic language tooling; whether in a browser environment or as standalone processes.

我们在该领域的原始事业Node.js被证明是一个非常成功的软件平台。人们发现它对于构建Web开发工具,构建独立的Web服务器以及许多其他用例很有用。但是,Node是在2009年设计的,当时JavaScript是一种非常不同的语言。出于必要,Node必须发明概念,这些概念后来被标准组织采纳,并以不同的方式添加到语言中。在“节点中的设计错误”演示文稿中,对此进行了更详细的讨论。由于Node拥有大量用户,因此发展该系统既困难又缓慢。

Our original undertaking in this area, Node.js, proved to be a very successful software platform. People have found it useful for building web development tooling, building standalone web servers, and for a myriad of other use-cases. Node, however, was designed in 2009 when JavaScript was a much different language. Out of necessity, Node had to invent concepts which were later taken up by the standards organizations and added to the language differently. In the presentation Design Mistakes in Node, this is discussed in more detail. Due to the large number of users that Node has, it is difficult and slow to evolve the system.

随着JavaScript语言的不断变化以及诸如TypeScript之类的新添加功能,构建Node项目可能会成为一项艰巨的工作,涉及管理构建系统和其他繁重的工具,这些工具摆脱了动态语言脚本的乐趣。此外,通过NPM存储库从根本上集中了链接到外部库的机制,这不符合Web的理想。

With the changing JavaScript language, and new additions like TypeScript, building Node projects can become an arduous endeavor, involving managing build systems and other heavy handed tooling that takes away from the fun of dynamic language scripting. Furthermore the mechanism for linking to external libraries is fundamentally centralized through the NPM repository, which is not inline with the ideals of the web.

我们认为JavaScript和周围的软件基础架构已经发生了足够的变化,值得进行简化。我们寻求一种有趣且高效的脚本环境,可用于多种任务。

We feel that the landscape of JavaScript and the surrounding software infrastructure has changed enough that it was worthwhile to simplify. We seek a fun and productive scripting environment that can be used for a wide range of tasks.

A Web Browser for Command-Line Scripts

Deno是一个新的运行时,用于在Web浏览器之外执行JavaScript和TypeScript。

Deno is a new runtime for executing JavaScript and TypeScript outside of the web browser.

Deno试图提供一个独立的工具来快速编写复杂功能的脚本。Deno是(并将始终是)单个可执行文件。就像网络浏览器一样,它知道如何获取外部代码。在Deno中,单个文件可以定义任意复杂的行为,而无需任何其他工具。

Deno attempts to provide a standalone tool for quickly scripting complex functionality. Deno is (and always will be) a single executable file. Like a web browser, it knows how to fetch external code. In Deno, a single file can define arbitrarily complex behavior without any other tooling.

import { serve } from "https://deno.land/std@0.50.0/http/server.ts";

for await (const req of serve({ port: 8000 })) {
  req.respond({ body: "Hello World\n" });
}

在这里,将完整的HTTP服务器模块作为依赖项添加到一行中。没有其他配置文件,没有安装要做,只需 deno run example.js

Here a complete HTTP server module is added as a dependency in a single line. There are no additional configuration files, there is no install to do beforehand, just deno run example.js.

与浏览器一样,默认情况下,代码在安全的沙箱中执行。未经允许,脚本无法访问硬盘驱动器,打开网络连接或进行任何其他潜在的恶意操作。浏览器提供了用于访问相机和麦克风的API,但用户必须首先授予权限。Deno在终端中提供类似的行为。除非提供–allow-net命令行标志,否则以上示例将失败。

Also like browsers, code is executed in a secure sandbox by default. Scripts cannot access the hard drive, open network connections, or make any other potentially malicious actions without permission. The browser provides APIs for accessing cameras and microphones, but users must first give permission. Deno provides analogous behaviour in the terminal. The above example will fail unless the --allow-net command-line flag is provided.

Deno小心不要偏离标准化的浏览器JavaScript API。当然,并不是每个浏览器API都与Deno相关,但无论它们在哪里,Deno都不会偏离标准。

Deno is careful to not deviate from standardized browser JavaScript APIs. Of course, not every browser API is relevant for Deno, but where they are, Deno does not deviate from the standard.

First Class TypeScript Support

我们希望Deno适用于广泛的问题领域:从小型单行脚本到复杂的服务器端业务逻辑。随着程序变得越来越复杂,具有某种形式的类型检查变得越来越重要。TypeScript是JavaScript语言的扩展,允许用户选择提供类型信息。

We want Deno to be applicable to a wide range of problem domains: from small one-line scripts, to complex server-side business logic. As programs become more complex, having some form of type checking becomes increasingly important. TypeScript is an extension of the JavaScript language that allows users to optionally provide type information.

Deno无需其他工具即可支持TypeScript。运行时在设计时考虑了TypeScript。deno types 命令为Deno提供的所有内容提供类型声明。Deno的标准模块全部使用TypeScript编写。

Deno supports TypeScript without additional tooling. The runtime is designed with TypeScript in mind. The deno types command provides type declarations for everything provided by Deno. Deno’s standard modules are all written in TypeScript.

Promises All The Way Down

Node是在JavaScript具有Promises或async / await概念之前设计的。Node所承诺的对手是EventEmitter,它基于重要的API,即套接字和HTTP。除了异步/等待的人体工程学优势外,EventEmitter模式还存在背压问题。以TCP套接字为例。套接字在收到传入数据包时将发出“数据”事件。这些“数据”回调将以不受限制的方式发出,从而使事件充满整个过程。由于Node继续接收新的数据事件,因此基础TCP套接字没有适当的背压,因此远程发送方不知道服务器已超负荷并继续发送数据。为了缓解此问题,添加了 pause() 方法。这可以解决问题,但是需要额外的代码;而且由于泛洪问题仅在进程非常繁忙时才会出现,因此许多Node程序都可能被数据泛洪。结果是系统的尾部延迟时间很长。

Node was designed before JavaScript had the concept of Promises or async/await. Node’s counterpart to promises was the EventEmitter, which important APIs are based around, namely sockets and HTTP. Setting aside the ergonomic benefits of async/await, the EventEmitter pattern has an issue with back-pressure. Take a TCP socket, for example. The socket would emit “data” events when it received incoming packets. These “data” callbacks would be emitted in an unconstrained manner, flooding the process with events. Because Node continues to receive new data events, the underlying TCP socket does not have proper back-pressure, the remote sender has no idea the server is overloaded and continues to send data. To mitigate this problem, a pause() method was added. This could solve the problem, but it required extra code; and since the flooding issue only presents itself when the process is very busy, many Node programs can be flooded with data. The result is a system with bad tail latency.

在Deno中,套接字仍然是异步的,但是接收新数据需要用户显式 read()。正确构造接收套接字不需要额外的暂停语义。这不是TCP套接字独有的。系统的最低绑定层从根本上与承诺相关联-我们称这些绑定为“ ops”。Deno中以某种形式出现的所有回调均来自promise。

In Deno, sockets are still asynchronous, but receiving new data requires users to explicitly read(). No extra pause semantics are necessary to properly structure a receiving socket. This is not unique to TCP sockets. The lowest level binding layer to the system is fundamentally tied to promises - we call these bindings “ops”. All callbacks in Deno in some form or another arise from promises.

Rust有其自己的类似于承诺的抽象,称为期货。通过“ op”抽象,Deno使将Rust未来的API绑定到JavaScript promise中变得容易。

Rust has its own promise-like abstraction, called Futures. Through the “op” abstraction, Deno makes it easy to bind Rust future-based APIs into JavaScript promises.

Rust APIs

我们提供的主要组件是Deno命令行界面(CLI)。CLI是今天的1.0版本。但是Deno并不是一个整体的程序,而是设计为Rust板条箱的集合,以允许在不同的层进行集成。

The primary component that we ship is the Deno command-line interface (CLI). The CLI is the thing that is version 1.0 today. But Deno is not a monolithic program, but designed as a collection of Rust crates to allow integration at different layers.

deno_core箱子是Deno的裸露骨头版本。它不依赖于TypeScript或Tokio。它只是提供了我们的运营和资源基础架构。也就是说,它提供了一种将Rust期货绑定到JavaScript promise的有组织方式。CLI当然完全建立在deno_core之上。

The deno_core crate is a very bare bones version of Deno. It does not have dependencies on TypeScript nor on Tokio. It simply provides our Op and Resource infrastructure. That is, it provides an organized way of binding Rust futures to JavaScript promises. The CLI is of course built entirely on top of deno_core.

rusty_v8条板箱可为V8的C ++ API提供高质量的Rust绑定。该API尝试尽可能与原始C ++ API匹配。这是零成本的绑定-Rust中公开的对象与您在C ++中操作的对象完全相同。(例如,先前对Rust V8绑定的尝试强制使用了持久句柄。)板条箱提供了在Github Actions CI中内置的二进制文件,但它还允许用户从头开始编译V8并调整其许多构建配置。所有V8源代码均在包装箱中分发。最后,rusty_v8尝试成为一个安全的接口。它还不是100%安全的,但我们正在接近。能够以安全的方式与像V8这样复杂的VM进行交互非常令人惊讶,并且使我们能够发现Deno本身中的许多困难错误。

The rusty_v8 crate provides high quality Rust bindings to V8’s C++ API. The API tries to match the original C++ API as closely as possible. It’s a zero-cost binding - the objects that are exposed in Rust are exactly the object you manipulate in C++. (Previous attempts at Rust V8 bindings forced the use of Persistent handles, for example.) The crate provides binaries that are built in Github Actions CI, but it also allows users to compile V8 from scratch and adjust its many build configurations. All of the V8 source code is distributed in the crate itself. Finally rusty_v8 attempts to be a safe interface. It’s not yet 100% safe, but we’re getting close. Being able to interact with a VM as complex as V8 in a safe way is quite amazing and has allowed us to discover many difficult bugs in Deno itself.

Stability

我们保证在Deno中保持稳定的API。Deno有很多接口和组件,因此透明地了解我们所说的“稳定”是很重要的。我们发明的与操作系统交互的JavaScript API都可以在“ Deno”命名空间(例如Deno.open())中找到。这些已经过仔细检查,我们不会对它们进行向后不兼容的更改。

We promise to maintain a stable API in Deno. Deno has a lot of interfaces and components, so it’s important to be transparent about what we mean by “stable”. The JavaScript APIs that we have invented to interact with the operating system are all found inside the “Deno” namespace (e.g. Deno.open()). These have been carefully examined and we will not be making backwards incompatible changes to them.

尚未准备稳定的所有功能都隐藏在--unstable命令行标志后面。您可以在此处查看不稳定接口的文档。在后续版本中,其中一些API也将被稳定。

All functionality which is not yet ready for stabilization has been hidden behind the --unstable command-line flag. You can see the documentation for the unstable interfaces here. In subsequent releases, some of these APIs will be stabilized as well.

在全局名称空间中,您会找到各种其他对象(例如setTimeout()fetch())。我们已经尽力使这些界面与浏览器中的界面相同。但是如果发现意外的不兼容性,我们将发出更正。浏览器标准定义了这些接口,而不是我们。我们发布的所有更正均是错误修复,而不是界面更改。如果与浏览器标准API不兼容,则可以在主要版本之前更正该不兼容。

In the global namespace you’ll find all sorts of other objects (e.g. setTimeout() and fetch()). We’ve tried very hard to keep these interfaces identical to those in the browser; but we will issue corrections if we discover inadvertent incompatibilities. The browser standards define these interfaces, not us. Any corrections issued by us are bug fixes, not interface changes. If there is an incompatibility with a browser standard API, that incompatibility may be corrected before a major release.

Deno也有许多Rust API,即deno_core和rusty_v8条板箱。这些API都不是1.0。我们将继续对它们进行迭代。

Deno also has many Rust APIs, namely the deno_core and rusty_v8 crates. None of these APIs are at 1.0 yet. We will continue to iterate on them.

Limitations

重要的是要了解Deno不是Node的分支-它是一个全新的实现。Deno的开发仅两年时间,而Node的开发已超过十年。考虑到对Deno的兴趣,我们希望它会继续发展和成熟。

It’s important to understand that Deno is not a fork of Node - it’s a completely new implementation. Deno has been under development for just two years, while Node has been under development for over a decade. Given the amount of interest in Deno, we expect it to continue to evolve and mature.

对于某些应用程序而言,Deno可能是当今的不错选择,对于其他应用程序而言则尚未。这将取决于需求。我们希望对这些限制保持透明,以帮助人们在考虑使用Deno时做出明智的决定。

For some applications Deno may be a good choice today, for others not yet. It will depend on the requirements. We want to be transparent about these limitations to help people make informed decisions when considering to use Deno.

Compatibility

不幸的是,许多用户会发现与现有JavaScript工具的兼容性令人沮丧地缺乏。通常,Deno与Node(NPM)软件包不兼容。在https://deno.land/std/node/上建立了一个新生的兼容性层,但还远未完成。

Unfortunately, many users will find a frustrating lack of compatibility with existing JavaScript tooling. Deno is not compatible, in general, with Node (NPM) packages. There is a nascent compatibility layer being built at https://deno.land/std/node/ but it is far from complete.

尽管Deno采用强硬方法简化了模块系统,但最终Deno和Node是目标相似的非常相似的系统。随着时间的推移,我们希望Deno能够开箱即用地运行越来越多的Node程序。

Although Deno has taken a hardline approach to simplifying the module system, ultimately Deno and Node are pretty similar systems with similar goals. Over time, we expect Deno to be able to run more and more Node programs out-of-the-box.

HTTP Server Performance

我们不断跟踪Deno的HTTP服务器的性能。问候世界的Deno HTTP服务器每秒处理约25,000个请求,最大延迟为1.3毫秒。一个可比的Node程序每秒处理34,000个请求,最大延迟介于2到300毫秒之间。

We continuously track the performance of Deno’s HTTP server. A hello-world Deno HTTP server does about 25k requests per second with a max latency of 1.3 milliseconds. A comparable Node program does 34k requests per second with a rather erratic max latency between 2 and 300 milliseconds.

Deno的HTTP服务器是在本机TCP套接字顶部的TypeScript中实现的。Node的HTTP服务器使用C语言编写,并作为对JavaScript的高级绑定公开。我们一直拒绝将本地HTTP服务器绑定添加到Deno的冲动,因为我们要优化TCP套接字层,更常见的是优化op接口。

Deno’s HTTP server is implemented in TypeScript on top of native TCP sockets. Node’s HTTP server is written in C and exposed as high-level bindings to JavaScript. We have resisted the urge to add native HTTP server bindings to Deno, because we want to optimize the TCP socket layer, and more generally the op interface.

Deno是一个合适的异步服务器,每秒25k请求足以满足大多数目的。(如果不是,那么JavaScript可能不是最佳选择。)此外,由于普遍使用Promise(如上所述),我们期望Deno通常表现出更好的尾部延迟。综上所述,我们确实相信该系统还有更多的性能优势,我们希望在将来的版本中实现这一目标。

Deno is a proper asynchronous server and 25k requests per second is quite enough for most purposes. (If it’s not, probably JavaScript is not the best choice.) Furthermore, we expect Deno to generally exhibit better tail latency due to the ubiquitous use of promises (discussed above). All that said, we do believe there are more performance wins to be had in the system, and we hope to achieve that in future releases.

TSC Bottleneck

在内部,Deno使用Microsoft的TypeScript编译器检查类型并生成JavaScript。与V8解析JavaScript所花费的时间相比,它非常慢。在项目的早期,我们曾希望“ V8快照”在此能够带来重大改进。快照肯定有帮助,但是它仍然缓慢地令人满意。我们当然认为可以在现有TypeScript编译器的基础上进行一些改进,但是对我们来说很显然,最终需要在Rust中实现类型检查。这将是一项艰巨的任务,不会很快发生。但它可以在开发人员经历的关键路径上提供数量级的性能改进。TSC必须移植到Rust。如果您有兴趣合作解决此问题,请与我们联系。

Internally Deno uses Microsoft’s TypeScript compiler to check types and produce JavaScript. Compared to the time it takes V8 to parse JavaScript, it is very slow. Early on in the project we had hoped that “V8 Snapshots” would provide significant improvements here. Snapshots have certainly helped but it’s still unsatisfyingly slow. We certainly think there are improvements that can be done here on top of the existing TypeScript compiler, but it’s clear to us that ultimately the type checking needs to be implemented in Rust. This will be a massive undertaking and will not happen any time soon; but it would provide order of magnitude performance improvements in a critical path experienced by developers. TSC must be ported to Rust. If you’re interested in collaborating on this problem, please get in touch.

Plugins / Extensions

我们有一个新生的插件系统,用于通过自定义操作扩展Deno运行时。但是,此接口仍在开发中,并已标记为不稳定。因此,访问Deno提供的系统以外的本机系统很困难。

We have a nascent plugin system for extending the Deno runtime with custom ops. However this interface is still under development and has been marked as unstable. Therefore, accessing native systems beyond that which is provided by Deno is difficult.


原文地址:Deno 1.0
发布日期:2020-05-13
原文地址:Ryan Dahl, Bert Belder, and Bartek Iwańczuk


参考链接:

译者 » 陈帅华
发布日期 » 2020年5月17日 周日
更新日期 » 2020年6月11日 周四
上一篇 » 我读《自卑与超越》
下一篇 » 科目一考试经历
:)记录此刻想法
请选择登录方式,开始记录你的想法。
授权微博登录
授权Github登录