原文地址:https://deno.land/v12020-05-13RyanDahl、BertBelder和BartekIwańczuk动态语言是有用的工具。脚本允许用户将复杂的系统连接在一起并快速简洁地表达想法,而无需担心内存管理或构建系统等细节。近年来,Rust和Go等编程语言使得生成复杂的本机代码变得更加容易。这些项目是计算机基础设施的极其重要的发展。但是,我们声称拥有能够解决各种问题域的强大脚本环境仍然很重要。JavaScript是使用最广泛的动态语言,通过网络浏览器在每台设备上运行。大量的程序员精通JavaScript,并为优化它的执行付出了很多努力。通过ECMA国际等标准组织,该语言得到了认真、持续的改进。我们相信JavaScript是动态语言工具的自然选择;在浏览器环境中和作为独立进程。我们在该领域的最初尝试Node.js被证明是一个非常成功的软件平台。人们发现它对于构建Web开发工具、构建独立的Web服务器和许多其他用例很有用。然而,Node是在2009年设计的,当时JavaScript是一种非常不同的语言。出于必要,Node不得不发明概念,这些概念后来被标准机构采用,并以不同的方式添加到语言中。这在“Node中的设计错误”演示文稿中有更详细的讨论。由于Node的大量用户,系统的发展非常困难且缓慢。随着JavaScript语言的不断变化和TypeScript等新功能的出现,构建Node项目可能成为一项艰巨的任务,涉及管理构建系统和其他繁重的工具,这些工具剥夺了动态语言脚本编写的乐趣。此外,链接到外部库的机制主要通过NPM存储库集中,这不符合网络的理想。我们认为JavaScript和周围的软件基础设施已经发生了足够大的变化,需要进行简化。我们正在寻找适合各种任务的有趣且高效的脚本编写环境。1.AWebBrowserforCommand-LineScripts(AWebBrowserforCommand-LineScripts)Deno是一种新的运行时,用于在Web浏览器之外执行JavaScript和TypeScript。Deno试图提供一个独立的工具来快速编写复杂函数的脚本。Deno是(并将永远是)一个单一的可执行文件。就像网络浏览器一样,它知道如何获取外部代码。在Deno中,单个文件可以定义任意复杂的行为,而无需任何额外的工具。import{serve}from"https://deno.land/std@0.50.0/http/server.ts";forawait(constreqofserve({port:8000})){req.respond({body:"HelloWorld\n"});}这里一个完整的HTTP服务器模块被添加为一行中的依赖项。没有额外的配置文件,也不需要事先安装,只需运行example.js即可。在这里,在一行中添加了一个完整的HTTP服务器模块作为依赖项。没有额外的配置文件,没有安装,只是deno运行example.js。与浏览器一样,代码默认在安全沙箱中执行。未经许可,脚本无法访问硬盘驱动器、打开网络连接或执行任何其他潜在的恶意操作。浏览器提供访问摄像头和麦克风的API,但用户必须先授予权限。Deno在终端中提供了类似的行为。除非提供--allow-net命令行标志,否则上述示例将失败。Deno注意不要偏离标准浏览器JavaScriptapi。当然,并非每个浏览器API都与Deno相关,但无论它们在哪里,Deno都不会偏离标准。2.FirstClassTypeScriptSupport(一流的TypeScript支持)我们希望Deno适用于广泛的问题领域:从小型的单行脚本到复杂的服务器端业务逻辑。随着程序变得越来越复杂,进行某种形式的类型检查变得越来越重要。TypeScript是JavaScript语言的扩展,允许用户有选择地提供类型信息。Deno无需额外工具即可支持TypeScript。运行时在设计时就考虑到了TypeScript。denotypes命令为Deno提供的所有内容提供类型声明。Deno的标准模块都是用TypeScript编写的。3、贯穿始终的承诺(PromisesAllTheWayDown)Node是在JavaScript有Promises和async/await概念之前设计的。Promises的Node对应物是EventEmitter,它基于重要的API,即套接字和HTTP。除了async/await的工程优势外,EventEmitter模式还存在背压问题。以TCP套接字为例。套接字在接收到传入数据包时将发出“数据”事件。这些“数据”回调将以无限制的方式发出,用事件淹没流程。由于Node不断接收新的数据事件,底层TCP套接字没有适当的背压,因此远程发送方不知道服务器超载并继续发送数据。为了缓解这个问题,添加了pause()方法。这解决了问题,但需要额外的代码;并且由于泛洪问题只会在进程非常繁忙的时候出现,所以很多Node程序很可能会被数据泛滥。结果是一个具有高尾延迟的系统。在Deno中,套接字仍然是异步的,但接收新数据需要用户显式地rean()。正确构造的接收套接字不需要额外的暂停语义。这不是TCP套接字独有的。系统的最低绑定层从根本上与承诺相关——我们称这些绑定为“ops”。Deno中某种形式的所有回调都来自承诺。Rust有自己的类似承诺的抽象,称为Futures。通过“op”抽象,Deno可以轻松地将RustFutures的API绑定到JavaScriptpromises中。4.RustAPIs我们提供的主要组件是Deno命令行界面(CLI)。CLI现在是1.0版。但Deno不是一个单一的程序,而是设计为Rustcrates的集合,以允许在不同层进行集成。deno_core是一个非常简单的Deno版本。它不依赖于TypeScript或Tokio。它只是提供我们的运营和资源基础设施。也就是说,它提供了一种将Rust期货绑定到JavaScript承诺的方法。CLI当然是完全构建在deno_core之上的。rusty_v8crates为V8的C++API提供高质量的Rust绑定。API尝试尽可能接近地匹配原始C++API。这是零成本绑定。Rust中公开的对象与您在C++中操作的对象完全相同。(例如,之前尝试绑定RustV8强制持久控制。)该箱子提供了在GithubActionsCI中构建的二进制文件,但它也允许用户从头开始编译V8并调整其许多构建配置。所有V8源代码都在板条箱中分发。最后,rusty_v8试图成为一个安全的接口。现在还不是100%安全,但我们已经接近了。能够以安全的方式与像V8这样复杂的VM进行交互是非常了不起的,并且让我们能够在Deno本身中找到许多棘手的错误。5.稳定性——我们保证Deno中的API稳定。Deno有很多接口和组件,所以对我们所说的“稳定”的含义保持透明很重要。我们发明的与操作系统交互的JavaScriptAPI都可以在“Deno”命名空间中找到(例如Deno.open())。这些已经过仔细检查,我们不会对它们进行向后不兼容的更改。所有尚未准备好稳定的功能都隐藏在--unstable命令行标志后面。您可以在此处查看不稳定接口的文档。其中一些API也将在后续版本中得到稳定。在全局名称空间中,您会发现各种其他对象(例如setTimeout()和fetch())。已尽一切努力使这些界面与浏览器中的界面相同。但如果发现意想不到的不兼容性,我们将进行更改。浏览器标准定义了这些接口,而不是我们。我们发布的所有更正都是错误修复,而不是界面更改。如果与浏览器标准API不兼容,则可以在主要版本发布之前纠正不兼容问题。Deno也有许多RustAPI,即deno_core和rusty_v8crates。这些API都不是1.0。我们将继续迭代它们。6.限制重要的是要了解Deno不是Node的分支——它是一个全新的实现。Deno的开发时间只有两年,而Node的开发时间已经超过十年。鉴于对Deno的兴趣,我们预计它会继续成长和成熟。对于某些应用程序来说,Deno现在可能是一个不错的选择,但对于其他应用程序来说还不是。这将取决于要求。我们希望对这些限制保持透明,以帮助人们在考虑使用Deno时做出明智的决定。6.1.兼容性不幸的是,许多用户会发现与现有JavaScript工具的兼容性令人沮丧。一般来说,Deno与Node(NPM)包不兼容。在https://deno.land/std/node/…上,但远未完成。尽管Deno采用强硬的方式来简化模块系统,但最终Deno和Node是非常相似的系统,有着相似的目标。随着时间的推移,我们希望Deno能够开箱即用地运行越来越多的Node程序。6.2HTTP服务器性能(HTTPServerPerformance)我们不断跟踪Deno的HTTP服务器的性能。hello-world的DenoHTTP服务器每秒处理大约25,000个请求,最大延迟为1.3毫秒。一个类似的Node程序每秒处理34,000个请求,最大延迟在2到300毫秒之间。Deno的HTTP服务器是通过原生TCP套接字在TypeScript中实现的。Node的HTTP服务器是用C语言编写的,并作为对JavaScript的高级绑定公开。我们一直抵制将本地HTTP服务器绑定添加到Deno的冲动,因为我们想要优化TCP套接字层,更普遍的是优化操作接口。6.3TSC瓶颈(TSCBottleneck)在内部,Deno使用微软的TypeScript编译器来检查类型并生成JavaScript。与V8解析JavaScript所花费的时间相比,它非常慢。在项目的早期,我们曾希望“V8快照”能够带来重大改进。快照肯定有帮助,但它仍然很慢。我们当然认为可以对现有的TypeScript编译器进行一些改进,但我们很清楚最终需要在Rust中实现类型检查。这将是一项艰巨的任务,而且不会很快发生。但它可以沿着开发人员经历的关键路径提供数量级的性能改进。TSC必须移植到Rust。如果您有兴趣就此问题进行合作,请联系我们。6.4插件/扩展我们有一个新生的插件系统,用于使用自定义操作扩展Deno运行时。但是,此接口仍在开发中,并已标记为不稳定。因此,访问非Deno提供的原生系统是很困难的。6.5致谢非常感谢帮助使这个版本成为可能的许多贡献者。特别是:@kitsonk,他在系统的许多部分都发挥了重要作用,包括(但不限于)TypeScript编译器主机、deno_typescript、deno包、deno安装、deno类型、流实现。@kevinkassimo在整个项目的历史中贡献了无数的错误修复。他的贡献包括定时器系统、TTY集成、wasm支持。Deno.makeTempFile、Deno.kill、Deno.hostname、Deno.realPath、std/node的要求、window.queueMircotask和REPL历史记录。他还创建了徽标。@kt3k实现了一个连续的基准系统(几乎在每一次重大重构中都发挥了作用)、信号处理程序、权限API和许多重要的错误修复。@nayeemrmn在Deno的许多部分贡献了错误修复,最值得注意的是他极大地改进了堆栈跟踪和错误报告,并且在稳定1.0API方面提供了很大帮助。@justjavac贡献了许多小但重要的修复,以使denoAPI与Web标准保持一致,最著名的是他编写了VSCodedeno插件。@zekth为std贡献了很多模块,包括std/encoding/csv、std/encoding/toml、std/http/cookies,以及许多其他错误修复。@axetroy帮助解决了所有相关的问题,修复了很多错误,并维护了VSCode插件。@afinch7实现了一个插件系统。@keroxp实现了一个websocket服务器并提供了许多错误修复。@cknight提供了大量文档和标准/节点polyfill。@lucacasonato几乎构建了整个deno.land站点。@hashrock做了很多令人惊叹的艺术作品,比如doc.deno.land的加载页面和该页面顶部的可爱图片!
