[译] Deno 1.0发布

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


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.


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.


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.


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 is a new runtime for executing JavaScript and TypeScript outside of the web browser.


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.


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


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


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.


我们保证在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.


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.


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.



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.


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.



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.


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’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 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


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
原文地址:Ryan Dahl, Bert Belder, and Bartek Iwańczuk


译者 » 陈帅华
发布日期 » 2020年5月17日 周日
更新日期 » 2020年6月11日 周四
上一篇 » 我读《自卑与超越》
下一篇 » 科目一考试经历