本文首发于公众号:符合预期的CoyPan
2020年5月13日,Deno终于正式发布了。Deno是基于V8 JavaScript引擎和Rust编程语言的JavaScript和TypeScript运行时。它是由Node.js之父Ryan Dahl建立的,专一于安全性和生产力。javascript
已经有了Node.js,为何还要搞一个Deno呢?按Ryan Dahl在2018年的一个演讲,他在设计Node.js的时候,犯了几个"错误"(演讲PPT我以前收集过,在公众号回复 前端学习 便可自行获取)。这几个"错误"是:前端
因而,Ryan Dahl决定开发一个新的JavaScript运行时。2年多后,Deno发布了。官网地址:java
赶忙来体验一下Deno。typescript
macOS下直接curl便可:curl -fsSL https://deno.land/x/install/install.sh | sh
shell
更多安装方式,请移步官网
下载完成后,将deno加入系统环境变量。首先npm
> vi ~/.bash_profile
接着,加入如下两行:编程
export DENO_INSTALL="/Users/pankeyu/.deno" export PATH="$DENO_INSTALL/bin:$PATH"
最后,执行:json
source ~/.bash_profile
而后,就能够在命令行愉快的执行deno了:浏览器
deno命令行的用法和node差很少。
想要执行脚本,直接deno run ${script}
便可。这里的script,也能够是一个线上文件。
直接执行代码,能够 deno eval "console.log(30933 + 404)"
。
deno支持如下命令:
bundle Bundle module and dependencies into single file cache Cache the dependencies completions Generate shell completions doc Show documentation for a module eval Eval script fmt Format source files help Prints this message or the help of the given subcommand(s) info Show info about cache or info related to source file install Install script as an executable repl Read Eval Print Loop run Run a program given a filename or url to the module test Run tests types Print runtime TypeScript declarations upgrade Upgrade deno executable to given version
更多信息,可使用deno help
查看。
从上面的bundle、test、fmt命令咱们能够看出来:deno原生支持打包,测试,格式化。
咱们使用官方的例子:
// server.ts import { serve } from "https://deno.land/std@0.50.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" }); }
执行deno server.ts
,命令行输出:
能够看到,直接报错了。这是deno的安全机制,须要加上--allow-net
这个参数,能够访问网络。
执行deno --allow-net server.ts
,命令行输出以下:
> deno --allow-net server.ts Compile file:///Users/pankeyu/Desktop/server.ts Download https://deno.land/std@0.50.0/http/server.ts Download https://deno.land/std@0.50.0/encoding/utf8.ts Download https://deno.land/std@0.50.0/io/bufio.ts Download https://deno.land/std@0.50.0/testing/asserts.ts Download https://deno.land/std@0.50.0/async/mod.ts Download https://deno.land/std@0.50.0/http/_io.ts Download https://deno.land/std@0.50.0/io/util.ts Download https://deno.land/std@0.50.0/path/mod.ts Download https://deno.land/std@0.50.0/path/win32.ts Download https://deno.land/std@0.50.0/path/posix.ts Download https://deno.land/std@0.50.0/path/common.ts Download https://deno.land/std@0.50.0/path/separator.ts Download https://deno.land/std@0.50.0/path/interface.ts Download https://deno.land/std@0.50.0/path/glob.ts Download https://deno.land/std@0.50.0/path/_constants.ts Download https://deno.land/std@0.50.0/path/_util.ts Download https://deno.land/std@0.50.0/fmt/colors.ts Download https://deno.land/std@0.50.0/testing/diff.ts Download https://deno.land/std@0.50.0/path/_globrex.ts Download https://deno.land/std@0.50.0/async/deferred.ts Download https://deno.land/std@0.50.0/async/delay.ts Download https://deno.land/std@0.50.0/async/mux_async_iterator.ts Download https://deno.land/std@0.50.0/textproto/mod.ts Download https://deno.land/std@0.50.0/http/http_status.ts Download https://deno.land/std@0.50.0/bytes/mod.ts http://localhost:8000/
浏览器打开http://localhost:8000/
,就能够看到输出的Hello World了。
也许你会疑惑为何要加一个--allow-net
的参数。这是Deno的安全策略。
从上面的例子能够看到,启动脚本时,deno会实时下载依赖到本地,下载完成后,再执行脚本逻辑。当咱们control+C退出后,再次执行脚本,命令行输出:
> deno --allow-net server.ts http://localhost:8000/
这一次不会再下载依赖了。
deno在第一次下载后,将依赖保存到了本地,而且这些依赖代码自己对用户是不可见的。这点和Node.js的node_modules彻底不一样。
若是咱们想从新下载依赖,须要在执行脚本的时候加上--reload:deno --allow-net --reload server.ts
。
若是咱们想查看脚本的依赖树,须要执行deno info server.ts
:
> deno info server.ts local: /Users/pankeyu/Desktop/server.ts type: TypeScript compiled: /Users/pankeyu/Library/Caches/deno/gen/file/Users/pankeyu/Desktop/server.ts.js map: /Users/pankeyu/Library/Caches/deno/gen/file/Users/pankeyu/Desktop/server.ts.js.map deps: file:///Users/pankeyu/Desktop/server.ts └─┬ https://deno.land/std@0.50.0/http/server.ts ├── https://deno.land/std@0.50.0/encoding/utf8.ts ├─┬ https://deno.land/std@0.50.0/io/bufio.ts ...
上面的简单例子还体现出下面几点:
--allow-net
这个flag,是会报错的。能够看出deno在安全方面的考量。Deno 是一个合适的异步服务器,每秒 25k 请求足以知足大多数目的,此外,因为广泛使用 Promise,Deno 须要有更好的尾部延迟。目前 Deno HTTP 服务器每秒处理约 25 000 个请求,最大延迟为 1.3 毫秒,与之相比,Node 程序每秒处理 34 000 个请求,最大延迟介于 2 到 300 毫秒之间。
这样看来,做者认为 Deno 的 HTTP 服务器还有更多的性能优点,并表示但愿在未来的版本中实现这一目标。
deno的http server性能能够在这里查看:https://deno.land/benchmarks
在Node中,提供了许多的内置模块,如:
const fs = require('fs'); const path = require('path'); ...
在deno中,也提供了很多的内置模块,可是并不支持Node同样的引入方式,而是挂在Deno
这个全局变量上。看一个例子:
// denoFs.js const readFile = Deno.readFile; const serverBuffer = await readFile('./server.ts'); console.log(serverBuffer);
执行脚本:
> deno run --allow-read denoFs.js Uint8Array(213) [ 105, 109, 112, 111, 114, 116, 32, 123, 32, 115, 101, 114, 118, 101, 32, 125, 32, 102, 114, 111, 109, 32, 34, 104, 116, 116, 112, 115, 58, 47, 47, 100, 101, 110, 111, 46, 108, 97, 110, 100, 47, 115, 116, 100, 64, 48, 46, 53, 48, 46, 48, 47, 104, 116, 116, 112, 47, 115, 101, 114, 118, 101, 114, 46, 116, 115, 34, 59, 10, 99, 111, 110, 115, 116, 32, 115, 32, 61, 32, 115, 101, 114, 118, 101, 40, 123, 32, 112, 111, 114, 116, 58, 32, 56, 48, 48, 48, 32, 125, 41, ... 113 more items ]
deno的模块化彻底遵循了es module。从前面的例子能够看出,deno能够直接import线上的资源包。对于本地资源,使用本地路径引入便可,可是必需要带上资源后缀(.ts,.js)。import就是申明依赖。
// world.ts export const world:string = 'world'; // hello.ts import { world } from './world.ts'; console.log(`Hello ${world}`);
执行脚本deno run hello.ts
:
> deno run hello.ts Compile file:///Users/pankeyu/Desktop/hello.ts Hello world
前面咱们提到,deno原生支持打包,测试,格式化等。咱们来试一试吧。
咱们使用上面的denoFs.js做为例子。
> deno bundle denoFs.js denoFs.output.js Bundling file:///Users/pankeyu/Desktop/deno/denoFs.js Emitting bundle to "denoFs.output.js" 2482 bytes emmited.
最终输出了一个denoFs.output.js文件,大概长成下面的样子,这个js文件也是能够直接由deno运行的。
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // This is a specialised implementation of a System module loader. // @ts-nocheck /* eslint-disable */ let System, __instantiateAsync, __instantiate; (() => { const r = new Map(); System = { register(id, d, f) { r.set(id, { d, f, exp: {} }); }, }; async function dI(mid, src) { ... } function gC(id, main) { ... } function gE(exp) { ... } function rF(main) { ... } async function gExpA(id) { ... } function gExp(id) { ... } __instantiateAsync = async (m) => { ... }; __instantiate = (m) => { ... }; })(); "use strict"; const readFile = Deno.readFile; const serverBuffer = await readFile("./server.ts"); console.log(serverBuffer); __instantiate("denoFs");
咱们使用上面的world.ts做为例子。
// world.ts export const world:string = 'world';
deno会从当前目录开始,逐级向上读取文件名为{*_,}test.{js,ts,jsx,tsx}
文件做为测试文件。咱们先写好测试用例:
// world.test.ts import { world } from "./world.ts"; Deno.test("env", () => { if (world !== 'world') { throw Error("wrong!"); } });
执行 deno test:
Compile file:///Users/pankeyu/Desktop/deno/.deno.test.ts running 1 tests test env ... ok (4ms) test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (4ms)
假设咱们待格式化的代码为:
// server.ts import { serve } from "https://deno.land/std@0.50.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" }) }
执行deno fmt server.ts
后,代码格式化完成:
// server.ts import { serve } from "https://deno.land/std@0.50.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" }); }
经过上面的探索,结合以前Ryan Dahl提到的Nodejs的"设计错误",能够稍微总结一下deno了。
一、deno从新实现了模块化机制,采用去中心化的设计,支持直接import线上的资源,再也不像Node同样依赖npm,摆脱了node_modules。同时,deno官方也提供了一个第三方库仓库:https://deno.land/std/。
二、deno的内置模块是挂在全局变量上的。
三、deno内置了typescript解析引擎,原生支持typescript。而且,deno也在拥抱W3C的规范(deno支持fetch)。
四、deno默认是安全的。从上面的例子中就能够看出,想要访问网络,访问文件系统等,都须要加上特定的参数才能够。
五、deno原生支持打包,测试,代码格式化等操做,旨在提升生产效率。
deno能够说是在重塑以前Nodejs的开发模式,其设计思想相比于Node.js,确实有进步的地方。对比做者以前提到的几条Node.js的"设计错误",deno一一解决了。
deno让人眼前一亮的去中心化模块依赖,或许可让前端cdn、生产环境自动化部署等技术获得进一步发展。不过deno想要达到Node.js的稳定性以及繁荣的生态,deno还有很长的路要走。
本文经过一个例子,不完整地对deno进行了介绍。Ryan Dahl大号练废了,又开了一个小号修炼。那么,这一次,你认为deno会火吗?