本文首發於公衆號:符合預期的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會火嗎?