最近 Nodejs 作者 Ryan Dahl 发布了 Deno 1.0 正式版,圈子一下沸腾起来了。或许你早在两年前就听说了这个东西,但是也有人不知道这个东西是什么,干什么用的,所以今天我将为大家来简单的聊一下这个将来可能会推翻 Node 的新轮子。
Deno 是一个基于 v8 、rust 和 Tokio 的 Javascript/Typescript 的安全运行时。它在内部嵌入了一个 typescript 的编译器。可以将 typescript 编译成 js 然后运行在 v8 上,并通过 c++ libdeno 实现 js 与 rust 的通信交互,当然 deno 也可以直接运行 Javascript 代码。
在过去的几年里,JS 标准引入了大量新的语法特性。影响最大的就是 Promis 和模块化。
对于 Node 来说,这两个东西支持的都不是很理想。由于历史原因,Node.js 必须支持回调函数,导致异步接口会有 Promise 和回调函数两种写法;同时,Node.js 自己的模块 CommonJS 与 ES 模块化不兼容,这样就导致无法完全支持 ES 模块化。
另一个原因就是 Node.js 的模块管理工具 Npm,逻辑越来越复杂;模块安装目录 npm_modules 非常庞杂,难以管理。Node.js 也几乎没有安全措施,用户只要下载了外部模块,就只好听任别人的代码在本地运行,进行各种读写操作。 然后 Node.js 的功能也不完整,导致外部工具层出不穷,让开发者疲劳不堪:webpack,babel,typescript 、eslint 、prettier.....
So,由于上面这些原因,作者 Ryan Dahl 决定放弃 Node.js ,重新写一个替代品,来彻底解决这些问题。
linux/mac
curl -fsSL https://deno.land/x/install/install.sh | sh
windows
iwr https://deno.land/x/install/install.ps1 | iex
详细可以参考官网查看:https://deno.land/
Deno 默认安全。相比之下,Node.js 默认拥有访问文件系统和网络的权限。 要在没有授权的情况下运行一个需要启动子进程的程序,比如:
deno run file-needing-to-run-a-subprocess.ts
运行后你会看到一条警示消息
error: Uncaught PermissionDenied: access to run a subprocess, run again with the --allow-run flag
相较于 Node,Deno 默认使用沙箱环境执行代码,这意味着运行环境没有操作以下模块权限:
必须使用参数,显式打开权限才可以,参数分别如下:
例如,要授予 Deno 对 /etc 目录的只读权限,可以这样:
deno --allow-read=/etc
Deno 使用浏览器一样的方式,通过 URL 来加载模块。很多人第一次见到在服务端的 import 语句中见到 URL 会感到有点困惑,但对我来说这还蛮好理解的:
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
通过使用 URL 来加载模块,Deno 就可以避免引入一个类似 npm 的中心化系统来发布 package,npm 最近受到了很多吐槽。 通过 URL 来引入代码,可以让包的作者们使用自己最喜爱的方式来维护和发布自己的代码。再也不会有 package.json 和 node_modules 了。 当我们启动应用之后,Deno 会下载所有被引用的文件,并将它们缓存到本地。一旦引用被缓存下来,Deno 就不会再去下载它们了,除非我们使用-- relaod 标志位去触发重新下载。
其实,你可以在本地文件中将已经引用的模块重新 export 出来,比如:
export { test, assertEquals } from "https://deno.land/std/testing/mod.ts";
假如上面这个文件叫 utils.ts 。现在,如果我们想再次使用 test 或者 assertEquals 方法,只需要像下面这样引用它们:
import { test, assertEquals } from './utils.ts';
另一种方式就是建一个引用映射表,比如像下面这样一个 JSON 文件:
{
"imports": {
"http/": "https://deno.land/std/http/"
}
}
然后 import 到代码里:
import { serve } from "http/server.ts";
最后为了让它生效,还需要通过--importmap 让 Deno 来引入 import 映射表:
deno run --importmap=import_map.json hello_server.ts
Deno 内置了开发者需要的各种功能,不再需要外部工具。打包、格式清理、测试、安装、文档生成、linting 、脚本编译成可执行文件等,都有专门命令。
下面是 Deno 的部分目录结构图
上图中圈出来的三个文件夹分别是
分别对应 Deno 的 api 层、中间层、和实现层;其中 js 中主要是 typescript 的代码,包含 typescript 的编译器和 Deno 暴露给用户的 api 。libdeno 中主要是 c++代码,用来加载 v8 实例,实现 typescript 和 rust 的通信。src 文件中主要是 rust 的代码,是 Deno 功能的具体实现。例如用户使用 File 实例的 write 方法来写文件,实际上是 api 层( typescript )通过中间层( libdeno )将数据传输给实现层( rust ),最终写文件操作由 rust 去完成。Deno 结合了 Typescript/Javascript 的易用性和 rust 的系统语言能力。
此图可以清晰的表示 js 和 rust 之间的逻辑关系。
就目前来看,Deno 还是一个比较新的东西,功能不稳定,周围生态还不够完整。
So,还不能完全取代 Node.js ,建议先不要用于生产环境,但是现在已经是一个能够使用的工具了,有时间的话可以造造轮子,研究一下也不是不可的。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.