【技术】 Deno 初探

分类: 技术 | 时间: 2020-08-02 | 评论: 暂无评论

很久很久很久没有写技术文章了,最近入职了字节跳动,整理了一些新技术,所以也在个人博客分享一下吧。

什么是Deno

Deno 和我们熟悉的Node.js类似,可以让开发者可以使用 JavaScript 语言开发后端服务
它的作者也是Ryan Dahl(Node.js 的作者)
官网描述其为“ 一个更安全的 JavaScript 和 TypeScript 运行时

运行时
运行时是一个运行环境,也叫运行平台,开发者可以使用指定的语言,基于这个环境开发应用。可以认为运行时就是一个舞台,能做什么事情,取决于舞台能提供什么道具。比如浏览器就是一个运行时,我们可以在浏览器上通过
JS 调用浏览器提供的 API 操作 DOM。

Deno的出现

既然已经有一个 Node.js,而且已经非常成功,为什么还要再搞一个 Deno呢 ?
2018年6月,Ryan Dahl 在德国柏林召开的 JSConf EU 会议上发表了名为 “10 Things I Regret About Node.js” 的演讲,在会上他回顾了在他认为当初开发 Node.js 时留下的10大遗憾,想要解决种种缺陷,但是 Node.js 已经广泛应用于各个领域,为保证兼容性,对 Node.js 底层进行大规模改造已经不现实。

Node.js的种种问题:
1.曾放弃原生支持 Promise: 造成了核心 API 的老化问题,得都一一更新成 Promise 版本才能解決。

2.没有谨慎思考安全性问题:使用 V8 的 Node.js 不需要“授权”,即可访问网络、档案系统,甚至是内存信息,在数据安全考量越来越重要的时代,会是 Node.js 被质疑的问题之一
3.Build System:在 Node 开发早期,Chrome V8 是以 GYP 构建系统,而 Node 也就沿用了 GYP,但不久后 Chrome 放弃 GYP 转而使用 GN,而 Node 已经无法挽回。因此 Node 成了目前在 V8 上唯一使用
GYP 的用戶,而 GN 速度比 GYP 快了将近 20 倍、文件可读性高且支持许多依赖。
4.Package.json 与 Npm 的集权问题
5.node_modules:node_modules 里的每一个 folder 并沒有标准,因此可以放置多余的版本或是任何其他档案和文件,这导致增加了模块解析复杂度。另外社区早已苦 node_modules
久已,嘲讽之是比黑洞更黑的存在:
6.index.js:若有了 package.json,其实就不需要默认加载 index.js,这让模块加载更加地复杂化。

所以 Ryan 宣布,他要开发一个全新的 JavaScript 运行时来解决存在的缺陷,这个项目就是 Deno了
Deno 的命名也很有趣,把 node(no de) 倒过来 deno(de no),意味着颠覆 Node

Deno 的特性

1.支持 TypeScript
2.支持ES Modules
3.默认采用沙箱模式运行代码,更安全
4.默认安全设置:除非显式开启,否则没有文件、网络权限,也不能访问运行环境
5.去中心化package:没有 node_modules 和 package.json,package 都通过 URL 来加载,加载时缓存到硬盘
6.脚本代码能被打包为一个单独的 JavaScript 文件
7.提供一套标准模块,确保与 Deno 兼容 deno.land/std
8.自带工具,如依赖检查器(deno info)和 代码格式化工具(deno fmt)
9.Top Level Await:不需要将 await 包裹在异步函数里
10.内置测试、浏览器兼容的API、执行Wasm二进制文件、Modern JS、ES Modules等等等……

与Node.js对比

12.png

如何使用Deno

既然这么nb,那么应该如何使用呢

安装环境

首先当然得安装运行环境,在MacOS下可以直接通过Shell安装

$ curl -fsSL https://deno.land/x/install/install.sh | sh

22.png
第一次安装需要配置下环境变量

$ touch ~/.bash_profile # 创建用户环境变量文件
$ vim ~/.bash_profile # 打开文件,将刚才命令行的配置语句粘贴进去,然后保存退出。
$ source ~/.bash_profile  # 让配置立即生效

运行deno -V,出现版本号就算安装成功了
32.png

先跑一个远程的项目试试

$ deno run https://deno.land/std/examples/welcome.ts

这是一个官方的demo,运行效果如下:(第一次运行会下载脚本)
42.png

跑本地项目

试着启动一个最简单的http服务器
在目录下创建一个main.ts文件,代码如下:

import { serve } from "https://deno.land/std@0.62.0/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
    req.respond({ body: "Hello World\n" });
}

如果使用VSCode编辑器,会因为不支持Deno语法报错,所以需要安装 Deno 插件
52.png
安装完后就不会报错了
62.png
运行deno run --allow-net main.ts
因为 Deno 采用沙箱模式运行代码,网络权限必须通过手动添加 flag --allow-net来开启,
运行结果如下:
72.png
82.png

试试其他功能

对TS的支持
102.png
完美支持TS类型检查
内置API

const dir = Deno.readDirSync(Deno.cwd())
for (const file of dir) {
    console.log(file)
}

可以直接使用Deno这个全局对象
Deno.cwd() 表示当前目录,Deno.readDirSync 表示读取目录信息,并返回一个可迭代对象
运行时需要赋予--allow-read权限,不然会报错

deno run --allow-read t11.ts

可以直接打印Deno对象看看
112.png

异步操作返回 Promise

const file = await Deno.create("./tttt.txt");
console.log(file);

Deno 中异步操作都是返回的 Promise 对象,
并且支持top-level-await(允许开发者在 async 函数外部使用 await 字段),非常的方便

提供的标准模块

Deno 提供了一个没有外部依赖的实用开发库,减轻我们开发负担:
1.node:node API 兼容模块
2.io:二进制读写操作;
3.http:网络和 web 服务相关;
4.path:文件路径相关;
5.colors:输出有颜色的文字,类似 chalk 库;
6.printf:格式化输出,类似 C 语言的 printf;
7.tar:解压与压缩;
8.async:生成异步函数的;
9.bytes:二进制比较和查找等;
10.datetime:日期相关;
11.encoding:文本的与二进制的转化、CSV和对象转化、yarml 和对象转化等;
12.flags:命令行参数解析;
13.hash:字符转 sha1 和 sha256;
14.fs:文件系统模块,类似 node 的 fs 模块;
15.log:日志管理;
16.permissions:权限相关;
17.testing:测试和断言相关;
18.uuid:用于生成 UUID;
19.ws:WebSocket 相关;

内置工具

Deno 提供了一组实用的工具:
1.deno bundle: 打包文件
2.deno install: 可以将我们的代码生成可执行文件进行直接使用
3.deno fmt: 格式化
4.deno lint: 代码检查
5.deno test: 测试

bundle
就和 webpack 打包文件差不多,会把引用的依赖打包进一个文件
122.png
132.png

deno bundle t2.ts bundle.js  # 打包
deno run bundle.js  # 运行打包后文件

142.png
Install

deno install --allow-read t11.ts

152.png
执行后会生成一个可执行文件,并打印出文件目录
可以直接运行
162.png

权限列表

1.-A, --allow-all:允许所有权限,将禁用所有安全限制。
2.--allow-env:允许环境访问,例如读取和设置环境变量。
3.--allow-hrtime: 允许高精度时间测量。
4.--allow-net=<allow-net>: 允许网络访问。
5.--allow-plugin: 允许加载插件。
6.--allow-read=<allow-read> 允许读取文件系统。
7.--allow-run 允许运行子进程。子进程不在沙箱中运行,没有与 deno 进程相同的安全限制。
8.--allow-write=<allow-write> 允许写入文件系统。

使用权限白名单
--allow-read=/usr
仅允许访问 /usr 目录,如果尝试访问其他目录会失败。
--allow-net=bytedance.com
仅允许与bytedance域名建立网络连接,访问其他域名进程会失败。

可能遇到的问题

环境变量不生效
重开终端后,每次都得source .bash_profile才能让环境变量生效。
原因:在 ~/.bash_profile 中配置环境变量, zsh加载的是 ~/.zshrc文件,而 .zshrc文件中并没有定义任务环境变量。
解决办法:在.zshrc里面添加一行source .bash_profile

加了权限标志符依旧报错
172.png
Deno的权限标志符位置有严格限制,--allow-net--allow-read 之类的标志符不可以放到文件名后面,必须紧跟在deno run后面

远程模块更新后不会获取最新模块
因为Deno有本地缓存机制,远程代码在第一次运行时获取并缓存(所以在离线状态下也可用)
182.png
想要刷新缓存需要在执行时使用 --reload 标志符
deno run --allow-read main.ts --reload

其他

Deno最近版本更新迭代很快,可以多关注发布页,并使用deno upgrade命令更新版本
192.png

Deno未来发展

记得当初还有一个负面新闻,一大堆人在Issue里抱怨学不动的(也让Deno涨了波热度...)
202.png
不管怎么说,前端本是一个需要不断学习的领域,也要尽量拥抱机遇(万一Deno真成了呢?

是否会取代 Node.js ?

网上意见不是很统一,但大多人认为会共存,但不会取代。
Node.js 经过十多年的发展,已经成熟并被广泛应用。Deno 要做的事情,Node.js 都能做,没有特殊原因的话,已使用 Node.js 的应用不太会改用 Deno 重构。
但Deno如此高速迭代,未来也说不好。

相关网站

官网
官方入门文档
标准模块库
第三方模块库
中文手册:Github的中文文档项目,最近刚更新,看不懂英文的人的福音
Deno API 中文手册:Deno API 简体中文版项目
Deno 中文网:中文版官网
Deno 中文社区:中文社区,现在还不是特别活跃

大佬的演讲:我对 Node.js 遗憾的十件事 - Ryan Dahl - JSConf EU 2018(Bilibili)
阮一峰的教程:Deno 运行时入门教程:Node.js 的替代品

添加新评论