zl程序教程

您现在的位置是:首页 >  前端

当前栏目

只需5分钟,让你了解未来可能推翻Node的新轮子 Deno 1.0

Node 了解 未来 可能 分钟 1.0 轮子 Deno
2023-06-13 09:11:05 时间

前言

最近Nodejs作者Ryan Dahl发布了Deno 1.0正式版,圈子一下沸腾起来了。或许你早在两年前就听说了这个东西,但是也有人不知道这个东西是什么,干什么用的,所以今天我将为大家来简单的聊一下这个将来可能会推翻Node的新轮子。

正文

什么是Deno?

Deno是一个基于v8、rust和Tokio的Javascript/Typescript的安全运行时。它在内部嵌入了一个typescript的编译器。可以将typescript编译成js然后运行在v8上,并通过c++ libdeno实现js与rust的通信交互,当然deno也可以直接运行Javascript代码。

已经有了Node,为什么作者还要写一个Deno?

在过去的几年里,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,重新写一个替代品,来彻底解决这些问题。

如何安装Deno?

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默认使用沙箱环境执行代码,这意味着运行环境没有操作以下模块权限:

  • 环境
  • 网络
  • 文件系统读/写
  • 运行子进程

必须使用参数,显式打开权限才可以,参数分别如下:

  • --allow-read:打开读权限,可以指定可读的目录,比如--allow-read=/temp。
  • --allow-write:打开写权限。
  • --allow-net=google.com:允许网络通信,可以指定可请求的域,比如--allow-net=google.com。
  • --allow-env:允许读取环境变量。

例如,要授予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标志位去触发重新下载。

只能使用URL来引用模块吗?

其实,你可以在本地文件中将已经引用的模块重新export出来,比如:

export { test, assertEquals } from "https://deno.land/std/testing/mod.ts";

假如上面这个文件叫utils.ts。现在,如果我们想再次使用test或者assertEquals方法,只需要像下面这样引用它们:

import { test, assertEquals } from './local-test-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的命令

Deno内置了开发者需要的各种功能,不再需要外部工具。打包、格式清理、测试、安装、文档生成、linting、脚本编译成可执行文件等,都有专门命令。

  • deno bundle 将脚本和依赖打包
  • deno eval 执行代码
  • deno fetch 将依赖抓取到本地
  • deno fmt 代码的格式美化
  • deno help 等同于-h参数
  • deno info 显示本地的依赖缓存
  • deno install 将脚本安装为可执行文件
  • deno repl 进入 REPL 环境
  • deno run 运行脚本
  • deno test 运行测试

Deno的内部结构

下面是Deno的部分目录结构图

上图中圈出来的三个文件夹分别是

  • js
  • libdeno
  • src

分别对应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,建议先不要用于生产环境,但是现在已经是一个能够使用的工具了,有时间的话可以造造轮子,研究一下也不是不可的。