通俗易懂的 Deno 入門教程

Deno 感興趣,想嚐嚐鮮或快速入門 Deno 的小夥伴看過來,本文將從七個方面入手,帶你一步步學習 Deno 的相關知識,詳細的內容大綱以下圖所示:javascript

自從 Deno 1.0 正式發佈以後,Deno 的熱度漸漸褪去。但近期 Deno 團隊計劃刪除全部內部代碼構建時的 TS 類型檢查與捆綁,又把 Deno 再一次帶入你們的視野。html

下面咱們來經過知乎上 justjavac(迷渡大大) 一個高讚的回答來大體瞭解一下其主要緣由。java

來自 天豬 的提問: 如何評價 deno 計劃把一些內部模塊從 ts 改回 js ?

來自 justjavac 的高贊回答:node

先說緣由:根本緣由是 ts 沒法爲 Deno runtime 生成高性能的 js 代碼webpack

首先須要澄清一個誤區:Deno 並無放棄 TypeScript,Deno 依然是一個安全的 TS/JS runtime。git

編譯速度慢是一個方面,但不是根本緣由。rustc 的編譯速度也很慢,可是生成的代碼質量很高。tsc 確實也慢,若是 tsc 可以生成高性能的 js 代碼,那麼這點構建的時間成本是能夠接受的。可是目前來看 ts 沒法爲 Deno runtime 生成高性能的 js 代碼。或者說,Deno 團隊沒有找到 ts 生成高性能 js 代碼的方式。github

Deno 使用最新版 ts 和 v8,而 ts 和 v8 的實現目標都是 stage3,理論上 ts 只要簡單的作類型擦除就能夠直接運行在 v8 上。最初 Deno 團隊也是這麼想的。可是實際使用 ts 的狀況卻不是這麼理想。web

此處省略好多個字,這裏就不繼續 「搬運」 了,感興趣的小夥伴能夠仔細閱讀一下原文,文中 justjavac 詳細介紹了前因後果。chrome

原文地址:https://www.zhihu.com/questio...typescript

1、Deno 簡介

Deno 是一個 JavaScript/TypeScript 的運行時,默認使用安全環境執行代碼,有着卓越的開發體驗。

(圖片來源:https://deno.land/artwork

DenoNode.js 之父 Ryan Dahl 的另外一個大做,它跟 Node.js 的關係是這樣的:

"node".split("").sort().join(""); // Output: deno

那麼實際上 Deno 與 Node.js 之間有什麼區別呢?這裏阿寶哥就不展開介紹了,感興趣的小夥伴能夠閱讀 「 Deno 正式發佈,完全弄明白和 node 的區別」 這篇文章。

下面咱們步入正題,開始進入 Deno 的世界,Deno 含有如下功能特性:

  • 默認安全,外部代碼沒有文件系統、網絡、環境的訪問權限,除非顯式開啓。
  • 支持開箱即用的 TypeScript 的環境。
  • 只分發一個獨立的可執行文件(deno)。
  • 有着內建的工具箱,好比一個依賴信息查看器(deno info)和一個代碼格式化工具(deno fmt)。
  • 有一組通過審計的標準模塊,保證能在 Deno 上工做。
  • 腳本代碼能被打包爲一個單獨的 JavaScript 文件。

Deno 是一個跨平臺的運行時,即基於 Google V8 引擎的運行時環境,該運行時環境是使用 Rust 語言開發的,並使用 Tokio 庫來構建事件循環系統。Deno 創建在 V8RustTokio 的基礎上,它的架構以下:

(圖片來源:https://deno.land/manual/cont...

1.1 Rust

Rust 是由 Mozilla 主導開發的通用、編譯型編程語言。設計準則爲 「安全、併發、實用」,支持函數式、併發式、過程式以及面向對象的編程風格。Deno 使用 Rust 語言來封裝 V8 引擎,經過 libdeno 綁定,咱們就能夠在 JavaScript 中調用隔離的功能。

1.2 Tokio

Tokio 是 Rust 編程語言的異步運行時,提供異步事件驅動平臺,構建快速,可靠和輕量級網絡應用。利用 Rust 的全部權和併發模型確保線程安全。Tokio 構建於 Rust 之上,提供極快的性能,使其成爲高性能服務器應用程序的理想選擇。在 Deno 中 Tokio 用於並行執行全部的異步 IO 任務。

1.3 V8

V8 是一個由 Google 開發的開源 JavaScript 引擎,用於 Google Chrome 及 Chromium 中。V8 在運行以前將JavaScript 編譯成了機器代碼,而非字節碼或是解釋執行它,以此提高性能。更進一步,使用瞭如內聯緩存(inline caching)等方法來提升性能。有了這些功能,JavaScript 程序與 V8 引擎的速度媲美二進制編譯。在 Deno 中,V8 引擎用於執行 JavaScript 代碼。

2、安裝 Deno

Deno 可以在 Mac、Linux 和 Windows 上運行。Deno 是一個單獨的可執行文件,它沒有額外的依賴。你能夠經過如下方式來安裝它:

  • 使用 Shell(Mac 和 Linux):
$ curl -fsSL https://deno.land/x/install/install.sh | sh
  • 使用 PowerShell(Windows):
iwr https://deno.land/x/install/install.ps1 -useb | iex
  • 使用 Scoop (Windows):
scoop install deno
choco install deno
brew install deno
  • 使用 Cargo (Windows,Mac,Linux):
cargo install deno

Deno 也能夠手動安裝,只需從 github.com/denoland/deno/releases 下載一個 zip 文件。它僅包含一個單獨的可執行文件。在 Mac 和 Linux 上,你須要爲它設置執行權限。當你成功安裝以後,能夠經過執行 deno --version 命令來查看已安裝的 Deno 版本:

$ deno --version
deno 1.1.2
v8 8.5.216
typescript 3.9.2

2.1 deno_install

在安裝過程當中,若是遇到問題的話,你們能夠試試 justjavac(迷渡)大神提供的安裝腳本 —— deno_install。該腳本經過單行命令將 Deno 安裝到系統中(國內加速)。

2.1.1 安裝最新版

使用 Shell:

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

使用 PowerShell:

$ iwr https://x.deno.js.cn/install.ps1 -useb -outf install.ps1; .\install.ps1
# iwr https://x.deno.js.cn/install.ps1 -useb | iex
2.1.2 安裝某個特定版本

使用 Shell:

$ curl -fsSL https://x.deno.js.cn/install.sh | sh -s v0.41.0

使用 PowerShell:

$ iwr https://x.deno.js.cn/install.ps1 -useb -outf install.ps1; .\install.ps1 v0.41.0
更多詳細的信息能夠瀏覽 x.deno.js.cn 站點。

2.2 deno-cli

deno-cli 命令行界面提供了一組集成功能,讓你能夠沉浸在 Deno 的專有開發環境中。如下是 Deno 1.1.2 版本支持的全部子命令:

SUBCOMMANDS:
    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
    lint           Lint source files
    repl           Read Eval Print Loop
    run            Run a program given a filename or url to the module. Use '-' as a filename 
                   to read from stdin.
    test           Run tests
    types          Print runtime TypeScript declarations
    upgrade        Upgrade deno executable to given version

2.3 REPL

在命令中輸入 deno 命令,你就會啓動一個 REPL(Read-Execute-Print-Loop):

$ deno
Deno 1.1.2
exit using ctrl+d or close()
> 0.1 + 0.2
0.30000000000000004
> const name = "阿寶哥";
undefined
> console.log(name);
阿寶哥
undefined
「讀取-求值-輸出」循環(英語:Read-Eval-Print Loop,簡稱 REPL),也被稱作交互式頂層構件(英語:interactive toplevel),是一個簡單的,交互式的編程環境。這個詞經常用於指代一個 Lisp 的交互式開發環境,也能指代命令行的模式。

2.4 VSCode Deno extension

相信不少小夥伴都在使用 VSCode IDE 進行 Web 開發,對於 Deno 的開發者來講,必定不能錯過 Deno 官方開發的 Visual Studio Code Deno extension 擴展。

2.4.1 未安裝 Deno extension

若是咱們寫 from "./hello.ts" 這樣的語句,在 VSCode 中將會出現波浪號的錯誤信息。由於默認狀況下,TypeScript 項目不須要添加 .ts 擴展名。

ts(2691): An import path cannot end with a '.ts' extension. Consider importing './hello' instead.

Deno 容許從 URL 中導入模塊,可是 TypeScript 並不支持從 URL 中導入模塊。

ts(2307): Cannot find module ' https://deno.land/x/std/log/mod'.

2.4.2 已安裝 Deno extension

Deno 將遠程導入(imports)緩存在 $DENO_DIR 環境變量指定的特殊目錄中。若是未指定 $DENO_DIR,則默認爲系統的緩存目錄。

該插件能夠將遠程導入(remote imports)解析爲本地路徑。

(本章節圖片來源:https://marketplace.visualstu...

瞭解 VSCode Deno extension 更多的詳細信息,能夠閱讀 justjavac(迷渡) 大佬 我爲 VS Code 開發了一個 Deno 插件 這篇文章。

3、Deno 初體驗

3.1 Welcome 示例

相信一些讀者安裝完 Deno 已經火燒眉毛了,如今咱們立馬來體驗一下 Deno 應用程序。首先打開你熟悉的命令行,而後在命令行輸入如下命令:

$ deno run https://deno.land/std/examples/welcome.ts
Download https://deno.land/std/examples/welcome.ts
Warning Implicitly using master branch https://deno.land/std/examples/welcome.ts
Compile https://deno.land/std/examples/welcome.ts
Welcome to Deno 🦕

經過觀察以上輸出,咱們能夠知道當運行 deno run https://deno.land/std/examples/welcome.ts 命令以後,Deno 會先從 https://deno.land/std/examples/welcome.ts URL 地址下載 welcome.ts 文件,該文件的內容是:

console.log("Welcome to Deno 🦕");

當文件下載成功後,Deno 會對 welcome.ts 文件進行編譯,即編譯成 welcome.ts.js 文件,而後再經過 V8 引擎來執行編譯生成的 JavaScript 文件。須要注意的是,若是你在命令行從新運行上述命令,則會執行緩存中已生成的文件,並不會再次從網上下載 welcome.ts 文件。

$ deno run https://deno.land/std/examples/welcome.ts
Welcome to Deno 🦕

那如何證實再次執行上述命令時, Deno 會優先執行緩存中編譯生成的 JavaScript 文件呢?這裏咱們要先介紹一下 deno info 命令,該命令用於顯示有關緩存或源文件相關的信息:

$ deno info
DENO_DIR location: "/Users/fer/Library/Caches/deno"
Remote modules cache: "/Users/fer/Library/Caches/deno/deps"
TypeScript compiler cache: "/Users/fer/Library/Caches/deno/gen"

在上述的輸出信息中,咱們看到了 TypeScript compiler cache 這行記錄,很明顯這是 TypeScript 編譯器緩存的目錄,進入該目錄後,經過一層層的查找,咱們最終在 examples 目錄下找到了 welcome.ts.js 文件:

➜  examples ls
welcome.ts.buildinfo welcome.ts.js.map
welcome.ts.js        welcome.ts.meta

打開目錄中 welcome.ts.js 文件,咱們能夠看到如下內容:

"use strict";                                                                                                      
console.log("Welcome to Deno 🦕");
//#sourceMappingURL=data:application/json;base64,eyJ2Z...

下面咱們來修改該文件,在文件中添加一行輸出信息 console.log("Hello Semlinker, from Cache");,具體以下:

"use strict";
console.log("Hello Semlinker, from Cache");
console.log("Welcome to Deno 🦕");
//#sourceMappingURL=data:application/json;base64,eyJ2Z...

接着咱們在命令行中從新執行如下命令:

$ deno run https://deno.land/std/examples/welcome.ts
Hello Semlinker, from Cache
Welcome to Deno 🦕

那麼如今問題又來了,如何強制刷新緩存,即從新編譯 TypeScript 代碼呢?針對這個問題,在運行 deno run 命令時,咱們須要添加 --reload 標誌,來告訴 Deno 須要從新刷新指定文件:

$ deno run --reload https://deno.land/std/examples/welcome.ts
Download https://deno.land/std/examples/welcome.ts
Warning Implicitly using master branch https://deno.land/std/examples/welcome.ts
Compile https://deno.land/std/examples/welcome.ts
Welcome to Deno 🦕

除了 --reload 標誌以外,Deno run 命令還支持不少其餘的標誌,感興趣的讀者能夠運行 deno run --help 命令來查看更多的信息。

3.2 TCP Echo Server

前面咱們已經介紹瞭如何運行官方的 welcome 示例,下面咱們來介紹如何使用 Deno 建立一個簡單的 TCP echo 服務器。首先咱們建立一個 learn-deno 項目,而後在該項目下新建一個 quickstart 目錄,接着新建一個 echo_server.ts 文件並輸入如下代碼:

const listener = Deno.listen({ port: 8080 });

console.log("listening on 0.0.0.0:8080");
for await (const conn of listener) {
  Deno.copy(conn, conn);
}

for await...of 語句會在異步或者同步可迭代對象上建立一個迭代循環,包括 String,Array,Array-like 對象(好比 arguments 或者 NodeList),TypedArray,Map, Set 和自定義的異步或者同步可迭代對象。

for await...of 的語法以下:

for await (variable of iterable) {
statement
}

輸入完以上代碼以後,相信不少讀者會跟我同樣,直接在命令行運行如下命令:

➜  quickstart deno run ./echo_server.ts
Compile file:///Users/fer/LearnProjects/learn-deno/quickstart/echo_server.ts
error: Uncaught PermissionDenied: network access to "0.0.0.0:8080", run again with the --allow-net flag
    at unwrapResponse ($deno$/ops/dispatch_json.ts:43:11)
    at Object.sendSync ($deno$/ops/dispatch_json.ts:72:10)
    at Object.listen ($deno$/ops/net.ts:51:10)
    at Object.listen ($deno$/net.ts:152:22)
    at file:///Users/fer/LearnProjects/learn-deno/quickstart/echo_server.ts:1:23

很明顯是權限錯誤,從錯誤信息中,Deno 告訴咱們須要設置 --allow-net 標誌,以容許網絡訪問。爲何會這樣呢?這是由於 Deno 是一個 JavaScript/TypeScript 的運行時,默認使用安全環境執行代碼。下面咱們添加 --allow-net 標誌,而後再次運行 echo_server.ts 文件:

➜  quickstart deno run --allow-net ./echo_server.ts
listening on 0.0.0.0:8080

當服務器成功運行以後,咱們使用 nc 命令來測試一下服務器的功能:

➜  ~ nc localhost 8080
hell semlinker
hell semlinker

介紹完如何使用 Deno 建立一個簡單的 TCP echo 服務器,咱們再來介紹一下如何使用 Deno 建立一個簡單的 HTTP 服務器。

3.3 HTTP Server

與 TCP Server 同樣,在 quickstart 目錄下,咱們新建一個 http_server.ts 文件並輸入如下內容:

import { serve } from "https://deno.land/std@v0.50.0/http/server.ts";

const PORT = 8080;
const s = serve({ port: PORT });

console.log(` Listening on <http://localhost>:${PORT}/`);

for await (const req of s) {
  req.respond({ body: "Hello Semlinker\\n" });
}
友情提示:在實際開發過程當中,你能夠從 https://deno.land/std 地址獲取所需的標準庫版本。示例中咱們顯式指定了版本,固然你也能夠不指定版本,好比這樣: https://deno.land/std/http/se...

在上述代碼中,咱們導入了 Deno 標準庫 http 模塊中 serve 函數,而後使用該函數快速建立 HTTP 服務器,該函數的定義以下:

// https://github.com/denoland/deno/blob/master/std/http/server.ts
export function serve(addr: string | HTTPOptions): Server {
  if (typeof addr === "string") {
    const [hostname, port] = addr.split(":");
    addr = { hostname, port: Number(port) };
  }

  const listener = Deno.listen(addr);
  return new Server(listener);
}

serve 函數接收一個參數,其類型是 string | HTTPOptions,其中 HTTPOptions 接口的定義以下:

/** Options for creating an HTTP server. */
export type HTTPOptions = Omit<Deno.ListenOptions, "transport">;

export interface ListenOptions {
  /** The port to listen on. */
  port: number;
  /** A literal IP address or host name that can be resolved to an IP address.
   * If not specified, defaults to `0.0.0.0`. */
  hostname?: string;
}

當輸入的參數類型是字符串時,serve 函數會使用 : 冒號對字符串進行切割,獲取 hostnameport,而後包裝成對象賦值給 addr 參數,接着使用 addr 參數繼續調用 listen 函數進一步建立 listener 對象,最終調用 new Server(listener) 建立 HTTP 服務器。

建立完 HTTP 服務器,咱們來啓動該服務器,打開命令行輸入如下命令:

➜  quickstart deno run --allow-net ./http_server.ts 
Compile file:///Users/fer/LearnProjects/learn-deno/quickstart/http_server.ts
 Listening on <http://localhost>:8080/

接着打開瀏覽器,在地址欄上輸入 http://localhost:8080/ 地址,以後在當前頁面中會看到如下內容:

Hello Semlinker\n

3.4 Cat 命令

介紹完如何使用 Deno 搭建一個 HTTP 服務器,接下來咱們再來介紹如何使用 Deno 開發一個簡單的 cat 命令。在 Linux 系統中,cat 命令用於鏈接文件並打印到標準輸出設備上。 如今咱們在 quickstart 目錄下,新建一個 cat.ts 文件並輸入如下內容:

for (let i = 0; i < Deno.args.length; i++) {
  let filename = Deno.args[i];
  let file = await Deno.open(filename);
  await Deno.copy(file, Deno.stdout);
  file.close();
}

在以上代碼中,咱們使用了 Deno 命名空間下的 3 個 API,它們的做用以下:

  • Deno.args:獲取腳本接收的參數;
  • Deno.open:用於打開文件,返回一個 Promise 對象,resolve 後返回一個 Deno.File 對象;
  • Deno.copy:用於執行拷貝操做,實現從源到目標的拷貝。當遇到 EOF 或發生錯誤時,會中止拷貝操做。調用該方法後,也會返回一個 Promise 對象,resolve 後會返回已複製的字節數。

因爲 Deno 是一個 JavaScript/TypeScript 的運行時,默認使用安全環境執行代碼。所以在運行 cat.ts 腳本時,咱們要設置 --allow-read 標誌 ,已容許文件系統讀訪問。即具體的腳本以下所示:

➜  quickstart deno run --allow-read cat.ts echo_server.ts

以上命令成功運行後,控制檯會輸出如下結果:

const listener = Deno.listen({ port: 8080 });

console.log("listening on 0.0.0.0:8080");
for await (const conn of listener) {
  Deno.copy(conn, conn);
}

快速體驗完 Deno,要進行實際項目開發,咱們還得了解一下如何調試 Deno 應用程序,因此下面咱們將介紹如何使用 Chrome Devtools 和 VSCode 調試 Deno 應用程序。

4、調試 Deno

Deno 支持 V8 Inspector Protocol。使用 Chrome Devtools 或其餘支持該協議的客戶端(好比 VSCode)可以調試 Deno 程序。要啓用調試功能,用 --inspect--inspect-brk 選項運行 Deno,對應的選項描述以下:

--inspect=<HOST:PORT>
  activate inspector on host:port (default: 127.0.0.1:9229)

--inspect-brk=<HOST:PORT>
  activate inspector on host:port and break at start of user script

--inspect 選項容許在任什麼時候間點鏈接調試器,而 --inspect-brk 選項會等待調試器鏈接,在第一行代碼處暫停執行。

4.1 Chrome Devtools

讓咱們用 Chrome 開發者工具來調試一個簡單的程序,咱們將使用來自 stdfile_server.ts,這是一個簡單的靜態文件服務。

使用 --inspect-brk 選項,在第一行代碼處暫停執行。

$ deno run --inspect-brk --allow-read --allow-net https://deno.land/std@v0.50.0/http/file_server.ts
Debugger listening on ws://127.0.0.1:9229/ws/1e82c406-85a9-44ab-86b6-7341583480b1
Download https://deno.land/std@v0.50.0/http/file_server.ts
Compile https://deno.land/std@v0.50.0/http/file_server.ts
...

打開 chrome://inspect,點擊 Target 旁邊的 Inspect

進一步瞭解更詳細的調試說明,可訪問 https://deno.land/manual/tool... URL 地址。

4.2 VSCode

Deno 能夠在 VSCode 中調試。插件的官方支持正在開發中 https://github.com/denoland/v...,固然咱們也能夠經過手動提供 launch.json 配置,來鏈接調試器:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Deno",
      "type": "node",
      "request": "launch",
      "cwd": "${workspaceFolder}",
      "runtimeExecutable": "deno",
      "runtimeArgs": ["run", "--inspect-brk", "-A", "<entry_point>"],
      "port": 9229
    }
  ]
}

注意:將 <entry_point> 替換爲實際的腳本名稱。

下面讓咱們來嘗試一下調試本地源文件,建立 server.ts

import { serve } from "https://deno.land/std@v0.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" });
}

<entry_point> 改成 server.ts,而後運行。

(圖片來源:https://deno.land/manual/tool...

(圖片來源:https://deno.land/manual/tool...

5、Deno Web API

Deno 還支持 W3C 標準規範,所以像 fetchsetTimeoutBlobWorker 等 API 均可以被直接使用。目前 Deno 已實現瞭如下 Web APIs:

出於篇幅考慮考慮,阿寶哥不打算介紹上面全部 Web APIs,只打算簡單介紹一下 Blob API 和 Worker API。

5.1 Blob API

Blob(Binary Large Object)表示二進制類型的大對象。在數據庫管理系統中,將二進制數據存儲爲一個單一個體的集合。Blob 一般是影像、聲音或多媒體文件。在 JavaScript 中 Blob 類型的對象表示不可變的相似文件對象的原始數據。

Blob 由一個可選的字符串 type(一般是 MIME 類型)和 blobParts 組成:

MIME(Multipurpose Internet Mail Extensions)多用途互聯網郵件擴展類型,是設定某種擴展名的文件用一種應用程序來打開的方式類型,當該擴展名文件被訪問的時候,瀏覽器會自動使用指定應用程序來打開。多用於指定一些客戶端自定義的文件名,以及一些媒體文件打開方式。

常見的 MIME 類型有:超文本標記語言文本 .html text/html、PNG圖像 .png image/png、普通文本 .txt text/plain 等。

5.1.1 構造函數

Blob 構造函數的語法爲:

var aBlob = new Blob(blobParts, options);

相關的參數說明以下:

  • blobParts:它是一個由 ArrayBuffer,ArrayBufferView,Blob,DOMString 等對象構成的數組。DOMStrings 會被編碼爲 UTF-8。
  • options:一個可選的對象,包含如下兩個屬性:

    • type —— 默認值爲 "",它表明了將會被放入到 blob 中的數組內容的 MIME 類型。
    • endings —— 默認值爲 "transparent",用於指定包含行結束符 \n 的字符串如何被寫入。 它是如下兩個值中的一個: "native",表明行結束符會被更改成適合宿主操做系統文件系統的換行符,或者 "transparent",表明會保持 blob 中保存的結束符不變。
5.1.2 屬性

前面咱們已經知道 Blob 對象包含兩個屬性:

  • size(只讀):表示 Blob 對象中所包含數據的大小(以字節爲單位)。
  • type(只讀):一個字符串,代表該 Blob 對象所包含數據的 MIME 類型。若是類型未知,則該值爲空字符串。
5.1.3 方法
  • slice([start[, end[, contentType]]]):返回一個新的 Blob 對象,包含了源 Blob 對象中指定範圍內的數據。
  • stream():返回一個能讀取 blob 內容的 ReadableStream
  • text():返回一個 Promise 對象且包含 blob 全部內容的 UTF-8 格式的 USVString
  • arrayBuffer():返回一個 Promise 對象且包含 blob 全部內容的二進制格式的 ArrayBuffer

這裏咱們須要注意的是,Blob 對象是不可改變的。咱們不能直接在一個 Blob 中更改數據,可是咱們能夠對一個 Blob 進行分割,從其中建立新的 Blob 對象,將它們混合到一個新的 Blob 中。這種行爲相似於 JavaScript 字符串:咱們沒法更改字符串中的字符,但能夠建立新的更正後的字符串。

5.1.4 使用示例
let myBlobParts = ["<html><h2>Hello Semlinker</h2></html>"]; 
let myBlob = new Blob(myBlobParts, {
  type: "text/html",
  ending: "transparent",
}); 

console.log(myBlob.size + " bytes size");
console.log(myBlob.type + " is the type");

以上代碼使用 deno run deno-blob.ts 命令運行後,命令行會輸出如下結果:

37 bytes size
text/html is the type

5.2 Worker API

Web Worker 是 HTML5 標準的一部分,這一規範定義了一套 API,它容許一段 JavaScript 程序運行在主線程以外的另一個線程中。Web Worker 的做用,就是爲 JavaScript 創造多線程環境,容許主線程建立 Worker 線程,將一些任務分配給後者運行。

在主線程運行的同時,Worker 線程在後臺運行,二者互不干擾。等到 Worker 線程完成計算任務,再把結果返回給主線程。這樣的好處是,能夠在獨立線程中處理一些計算密集型或高延遲的任務,從而容許主線程(一般是 UI 線程)不會所以被阻塞或拖慢。

(圖片來源:https://viblo.asia/p/simple-w...

Worker() 構造函數建立一個 Worker 對象,該對象執行指定的URL腳本。這個腳本必須遵照同源策略 。若是違反同源策略,則會拋出一個 SECURITY_ERR 類型的 DOMException。

5.2.1 Worker 構造函數

Worker 構造函數的語法爲:

const myWorker = new Worker(aURL, options);

相關的參數說明以下:

  • aURL:是一個 DOMString 表示 worker 將執行的腳本的 URL。它必須遵照同源策略。
  • options(可選):包含可在建立對象實例時設置的選項屬性的對象。可用屬性以下:

    • type:用以指定 Worker 類型的 DOMString 值. 該值能夠是 classic 或 module。若是未指定,將使用默認值 classic。
    • credentials:用以指定 worker 憑證的 DOMString 值。該值能夠是 omit,same-origin 或 include。若是未指定,或者 type 是 classic,將使用默認值 omit (不要求憑證)。
    • name:在 DedicatedWorkerGlobalScope 的狀況下,用來表示 Worker 的 scope 的一個 DOMString 值,主要用於調試目的。

須要注意的是,在建立 Web Worker 的時候,可能會出現如下異常:

  • 當 document 不被容許啓動 worker 的時候,將拋出一個 SecurityError 異常。好比:若是提供的 aURL 有語法錯誤,或者與同源策略相沖突(跨域訪問)。
  • 若是 worker 的 MIME 類型不正確,將拋出一個 NetworkError 異常。worker 的 MIME 類型必須是 text/javascript
  • 若是 aURL 沒法被解析(格式錯誤),將拋出一個 SyntaxError 異常。
5.1.2 使用示例

main.ts

const worker = new Worker(new URL("worker.ts", import.meta.url).href, {
  type: "module",
});

worker.onmessage = (e: MessageEvent) => {
  console.log(`Main: Received msg from deno worker - ${e.data}`);
};

worker.postMessage("Hello Deno");

worker.ts

self.onmessage = (e: MessageEvent) => {
  console.log(`Worker: Received from main - ${e.data}`);
  self.postMessage("Hello Semlinker");
};

以上代碼使用 deno run --allow-read main.ts 命令運行後,命令行會輸出如下結果:

Worker: Received from main - Hello Deno
Main: Received msg from deno worker - Hello Semlinker

6、Deno Web 開發

相信接觸過 Node.js 的讀者對 Express、Hapi、Koa 這些 Web 應用開發框架都不會陌生,在 Deno 平臺中若是你也想作 Web 應用開發,能夠考慮直接使用如下現成的框架:

  • abc:A better Deno framework to create web application。
  • deno-drash:A REST microframework for Deno with zero dependencies。
  • deno-express:Node Express way for Deno。
  • oak:A middleware framework for Deno's net server 🦕 。
  • pogo:Server framework for Deno。
  • servest:🌾A progressive http server for Deno🌾。

寫做本文時,目前 Star 數最高的項目是 Oak,下面咱們來簡單介紹一下 Oak

A middleware framework for Deno's http server, including a router middleware.

This middleware framework is inspired by Koa and middleware router inspired by koa-router.

很顯然 Oak 的的靈感來自於 Koa,而路由中間件的靈感來源於 koa-router 這個庫。若是你之前使用過 Koa 的話,相信你會很容易上手 Oak。不信的話,咱們來看個示例:

import { Application } from "https://deno.land/x/oak/mod.ts";

const app = new Application();

app.use((ctx) => {
  ctx.response.body = "Hello Semlinker!";
});

await app.listen({ port: 8000 });

以上示例對於每一個 HTTP 請求,都會響應 "Hello Semlinker!"。只有一箇中間件是否是感受太 easy 了,下面咱們來看一個更復雜的示例(使用多箇中間件):

import { Application } from "https://deno.land/x/oak/mod.ts";

const app = new Application();

// Logger
app.use(async (ctx, next) => {
  await next();
  const rt = ctx.response.headers.get("X-Response-Time");
  console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`);
});

// Timing
app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  ctx.response.headers.set("X-Response-Time", `${ms}ms`);
});

// Hello World!
app.use((ctx) => {
  ctx.response.body = "Hello World!";
});

await app.listen({ port: 8000 });

爲了更好地理解 Oak 中間件流程控制,咱們來一塊兒回顧一下 Koa 大名鼎鼎的 「洋蔥模型」

從 「洋蔥模型」 示例圖中咱們能夠很清晰的看到一個請求從外到裏一層一層的通過中間件,響應時從裏到外一層一層的通過中間件。上述代碼使用 deno run --allow-net oak/oak-middlewares-demo.ts 成功運行後,咱們打開瀏覽器,而後訪問 http://localhost:8000/ URL 地址,以後在命令行會輸出如下結果:

GET http://localhost:8000/ - 0ms
GET http://localhost:8000/favicon.ico - 0ms

這裏咱們只是簡單介紹了 Oak,若是對 Oak 如何開發 REST API 感興趣的話,能夠閱讀阿寶哥 了不得的 Deno 實戰教程 這篇文章。

7、阿寶哥有話說

7.1 Deno 如何使用第三方模塊

截止目前(2020-06-30)爲止,Deno 支持的第三方庫的數目爲 707

(圖片來源:https://deno.land/x

下面咱們以你們熟悉的 lodash 爲例,來看一下如何使用第三方模塊。首先在搜索框中輸入 lodash,對應的搜索結果以下:

(圖片來源:https://deno.land/x

接着選擇你想要安裝的模塊,這裏阿寶哥選擇 deno_lodash 這個模塊,點擊該列表項會進入該模塊的詳情頁。而後你就能夠根據模塊的說明文檔來安裝使用模塊了,如下是文檔中該模塊的使用示例:

import _ from "https://deno.land/x/deno_lodash/mod.ts";

console.log(_.defaults({ 'a': 1 }, { 'a': 3, 'b': 2 }));
// → { 'a': 1, 'b': 2 }

console.log(_.partition([1, 2, 3, 4], (n:number) => n % 2));
// → [[1, 3], [2, 4]]

7.2 Deno 如何統一管理項目依賴

在 Deno 項目中可使用一個 deps.ts 文件來統一管理全部依賴,別的地方直接從 deps.ts 統一引入,例如 oak 項目的 deps.ts 以下所示:

// https://github.com/oakserver/oak/blob/main/deps.ts
export { copyBytes, equal } from "https://deno.land/std@0.59.0/bytes/mod.ts";
export { Sha1 } from "https://deno.land/std@0.59.0/hash/sha1.ts";
export { HmacSha256 } from "https://deno.land/std@0.59.0/hash/sha256.ts";

// 已省略部分代碼
// 3rd party dependencies
export {
  contentType,
  extension,
  lookup,
} from "https://deno.land/x/media_types@v2.3.8/mod.ts";
export {
  compile,
  parse as pathParse,
  pathToRegexp,
} from "https://raw.githubusercontent.com/pillarjs/path-to-regexp/v6.1.0/src/index.ts";

那麼如何查找這些模塊呢?除了在前面提到的 Deno 官網 第三方模塊 頁面查找以外,你也能夠在 pika 中尋找指定的模塊,若是搜索出來的結果能直接使用,不會報錯,代表該模塊能夠正常在 deno 中使用。

7.3 Deno 如何使用 npm 包

在 Deno 中若是要使用 npm 包,能夠利用 Deno 標準庫中提供的 createRequire 方法,具體使用方式以下:

import { createRequire } from "https://deno.land/std/node/module.ts";

const require = createRequire(import.meta.url);
// Loads native module polyfill.
const path = require("path");
// Loads extensionless module.
const cjsModule = require("./my_mod");
// Visits node_modules.
const leftPad = require("left-pad");

除此以外,Deno 還能夠藉助 jspm.io 的能力來調用 npm 的模塊,感興趣的小夥伴能夠閱讀 Deno藉助jspm使用npm 這篇文章。

7.4 如何用一個代碼庫來維護同時支持 Deno 和 npm 的模塊

儘管將模塊移植到 Deno 很是容易,可是你要維護兩個代碼庫卻很麻煩。因此若是你想只使用一個代碼庫來維護同時支持 Deno 和 npm 的模塊,這時你能夠考慮使用 denoify 這個工具。

denoify 是一個構建工具,該構建工具將旨在以 node 或 web 爲目標的 TypeScript 代碼庫做爲輸入,並將源文件的修改版本做爲 Deno模塊部署。

(圖片來源:https://github.com/garronej/d...

如下是使用 denoify 開發的模塊:

感興趣的小夥伴,能夠自行了解一下上述的模塊。另外,若是你也想要在項目中使用 denoify ,那麼能夠參考這個倉庫,該倉庫會一步步教你如何在項目中配置 denoify

8、總結

本文從七個方面入手,介紹了 Deno 入門相關的基礎知識,但願對 Deno 初學者能有一些幫助,固然有寫得很差的地方歡迎小夥伴們指出。Deno 如今還在高速地發展,標準庫還未正式發佈穩定的版本,寫做本文時,最新版本是 0.59.0。相比成熟的 Node.js 社區,Deno 社區還有很長一段路要走,感興趣的小夥伴們能夠持續關注它。

阿寶哥是在 Deno 1.0.0 發佈後才正式學習 Deno,目前也還在不斷學習中。對阿寶哥我的來講,近期比較感興趣的是 Deno Web API,所以近期也花了蠻多時間學習 Deno Web API 的實現。在學習過程當中,也遇到挺多問題的,這裏要感謝 justjavac(迷渡大大) 的耐心解答。

能看到這裏的小夥伴都是 「真愛」,最後感謝你們閱讀本教程,歡迎對 Deno 感興趣的小夥伴跟阿寶哥一塊兒交流和學習 Deno。

9、參考資源

10、推薦閱讀

相關文章
相關標籤/搜索