新的一年新的开始!新的东西,学起!(扶朕起来,朕还可以再学
它是 Node.js 的替代品。有了它,将来可能就不需要 Node.js 了。 ———— 阮一峰《Deno 运行时入门教程:Node.js 的替代品》
Deno 简介
Deno 是一个跨平台的运行时,即基于 Google V8 引擎的运行时环境,该运行时环境是使用 Rust 语言开发的,并使用 Tokio 库来构建事件循环系统。Deno 有以下优点:
- 默认安全。除非显式启用,否则不能访问文件,网络或环境
- 开箱即用的 TypeScript 支持
- 只分发一个可执行文件
- 具有内置的工具箱,比如依赖项检查工具(deno info)和 代码格式化工具(deno fmt)
- 拥有一组保证能够与 Deno 一起使用的经过审查的标准模块:
deno.land/std
- 脚本可以打包到一个 JavaScript 文件中
一些命令
执行 deno -h
或 deno --help
就能够显示 Deno 支持的子命令,以下列举一些主要使用的命令
- deno bundle:deno bundle [options]
[out_file] 将脚本和依赖打包 - deno fmt:代码格式化
- deno info:显示本地的依赖缓存
- deno install:将脚本安装为可执行文件
- deno repl:进入 REPL 环境
- deno run:运行脚本
与 Node.js 的区别
Deno 既然是 Node.js 的 ”替代品“,究竟解决了 Node.js 的哪些痛点呢?
模块引入的方式
Node 模块引入
Node 内置 API 通过模块引入的方式引入。
const path = require('fs') |
Deno 全局对象
在 Deno 中则是一个全局对象 Deno
的属性和方法
Deno.readFileSync('demo.txt') |
模块系统
在模块系统方面,这是 Deno 和 Node.js 差别最大的地方。
Node.js CommonJS 规范
Node.js 采用的是 CommonJS
模块规范。具体规范见 CommonJS 规范
const fs = require('fs') |
Deno 的模块规范
不同于 Node.js 的规范,Deno 所采用的模块规范是 ES Module 规范
import as fs from "https//deno.land/std/fs/mod.ts" |
在 Deno 中,可以直接 import url 来引用线上的资源,并且资源的扩展名和文件名不可以省略。
安全
这个安全主要体现在 Deno 的操作很多都需要提供权限,比如:
// demo.ts |
我们执行这段代码
$ deno run .\demo.ts |
这会告诉我们没有给予它 --allow-read
的权限,当我们给予它权限后,就能成功创建文件
$ deno run --allow-read --allow-write .\demo.ts |
Deno 的权限列表
-A, --allow-all
允许所有权限,这将禁用所有安全限制。--allow-env
允许环境访问,例如读取和设置环境变量。--allow-hrtime
允许高精度时间测量,高精度时间能够在计时攻击和特征识别中使用。--allow-net=<allow-net>
允许网络访问。您可以指定一系列用逗号分隔的域名,来提供域名白名单。--allow-plugin
允许加载插件。请注意:这是一个不稳定功能。--allow-read=<allow-read>
允许读取文件系统。您可以指定一系列用逗号分隔的目录或文件,来提供文件系统白名单。--allow-run
允许运行子进程。请注意,子进程不在沙箱中运行,因此没有与 deno 进程相同的安全限制,请谨慎使用。--allow-write=<allow-write>
允许写入文件系统。您可以指定一系列用逗号分隔的目录或文件,来提供文件系统白名单。
这里插一句不属于权限但是属于 run
的时候可以传入的选项 --unstable
,传递这个选项将允许在运行时使用不稳定的 API。
白名单
Deno 还可以设置白名单来控制权限的粒度。
deno run --allow-read=/etc https://deno.land/std@$STD_VERSION/examples/main.ts /etc/passwd |
可以使得文件系统能够访问 /etc
目录。
支持 TypeScript
Deno 原生支持 TS,这点对于一个 TS 使用者来说实在是太赞了。Node.js 中要使用 TypeScript 的话还需要 ts-node
之类的工具的支持。
无 node_modules
不同于 Node.js,Deno 并没有 node_modules 来进行包管理。但是 Deno 在每次初执行时,会进行依赖的下载和编译,我们可以通过 deno info
来查看
$ deno info [file_name] |
其实这就相当于是进行了包管理,编译后的文件,远程模块缓存都会放在相应的位置。
异步操作
Node 用回调的方式处理异步操作,而 Deno 则使用的是 Promise
// node |
这是实战
项目采用的框架是
oak
,应该是对应了 Node.js 的Koa
,如果之前使用过Koa
的话,使用oak
这个框架应该会很熟悉。
准备工作
因为笔者是用的 VSCode 在开发,所以在开始写 Deno 项目前我们先做好相关设置。
在 .vscode/settings.json
中写入设置
{ |
使得编辑器在写 deno 时能够进行代码提示。
虽然 Deno 说自己没有像 npmjs 那样的包管理中心,但其实他还是有属于自己的 Deno标准库,目前版本是 0.83.0
。
当我们要使用一些标准模块,比如 path
,我们就要去引入标准库。
项目结构
└── deno-demo |
入口文件
app.ts
import { Application } from "https://deno.land/x/oak/mod.ts"; |
从以上的代码来看,整个流程跟 Node.js 使用 Koa 开发几乎一样。
配置文件
configs.ts
const env = Deno.env.toObject(); |
在配置文件中配置 HOST
、PORT
、DB
等参数。
路由配置
routes.ts
import { Router } from "https://deno.land/x/oak/mod.ts"; |
路由文件也和使用 Koa-router
时的代码差不多。
定义模型(model)
定义模型在本项目中体现为定义了一个接口
model/todo.ts
export interface Todo { |
数据操作
service/db.ts
import { DB } from "../configs.ts"; |
数据的增删改查
详情见项目的 controllers
下的文件
Not Found
当 api 不能匹配到对应的路由时,返回 Not Found
信息
controllers/notFound.ts
import { Response } from "https://deno.land/x/oak/mod.ts"; |
中间件 Middlewares
我们定义了一个中间件 error.ts
来处理读不到数据的错误
moddlewares/error.ts
import { Response } from "https://deno.land/x/oak/mod.ts"; |
总结
在进行以上代码的写入后,我们就可以进行 run
整个项目了
注意 run
的时候要带上 -A
或 --allow-all
,意思是给予全部权限给当前项目。
deno run -A ./app.ts |
ok!整个项目就跑起来啦。这次 deno 的初体验也就完成了。完整代码的地址是 deno-demo。
注意事项
- 不能开代理。否则无法运行