Deno從零到架構級系列(一)——開篇

image

你們好,小弟飛狐。很久沒來思否了,再來帶來了的必定是乾貨。從Deno開始,飛狐帶來的絕對到目前爲止史無前例的Deno系列。話很少說,用技術說話。javascript

你學不動的 Deno 來了

還記得 Github 上那個讓人學不動的 Deno 麼?就在2020年5月13日,Deno1.0正式發佈。做爲新晉網紅運行時,Deno真的會替代 Node 嗎?這個問題能夠追溯到2018年,從Node之父 Ryan Dahl的演講提及,Ryan在演講中談及對Node有十大不滿之處,而且在演講的最後公佈了Deno項目。我在這裏只列三大新特性。java

  • 首先,Deno 做爲一個JavaScript/TypeScript 運行時,底層基於性能超高的 Rust 編寫,在性能和存儲安全上有先天的優點。
  • 其次,Deno 擁有完整的標準庫,再也不有 NPM 或 node_modules 文件夾,容許從任何地方導入所需模塊。
  • 另外,Deno 集成 TypeScript,再也不像之前同樣藉助工具編譯,而是經過內部轉換。不過彷佛又要剝離。

綜上所述,你會發現,Deno真的是青出於藍而勝於藍。是否替代,只是時間問題而已。我也看到不少人在作deno和node的性能比較,但在目前我認爲作這二者的性能比較徹底沒有必要。node

image

安裝

咱們一開始甭管deno底層用的go仍是rust,爲啥要從go換成rust、或者是deno的技術架構是咋樣?這些目前都不要關心,咱們就把deno當成一個新的運行時,只作運行時。從零到一,經過搭建一套腳手架,再慢慢去深刻。Deno能夠在Mac、Linux、Windows三大系統上運行。Deno也不須要其餘依賴。經過以下方式安裝:golang

  • 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
  • Homebrew (Mac): brew install deno
  • Chocolatey (Windows): choco install deno
  • Scoop (Windows): scoop install deno

第一個例子也是來自官方,每一行我都加了解釋。以下:spring

// 建立文件 /server.ts
// 不須要像node同樣去npm,這裏直接引入
import { serve } from "https://deno.land/std@0.63.0/http/server.ts";
// 構建服務,設置端口
const s = serve({ port: 8000 });
// 這裏是直接返回
for await (const req of s) {
  req.respond({ body: "Hello World\\n" });
}

整個代碼很是簡單,語法也是ts,和node很是像。有node基礎的同窗直接入手。typescript

運行命令:deno run --allow-net ./server.ts,npm

而後在瀏覽器打開http://localhost:8000,就能夠看到hello world了,以下圖:瀏覽器

image

框架之選

衆所周知,node的框架比較成熟,國外的有nest.js、國內的有egg.js。而目前deno的生態其實並不成熟,框架也都是模仿其餘框架,多的就不介紹了,這裏我給你們推薦兩個框架。以下:安全

  • oak
  • alosaur

推薦oak的緣由很簡單,就是咱們整個腳手架搭建都是基於oak的。oak模仿的是node的框架koa,從名字也能夠看出來。 而推薦alosaur的緣由就一點,可學性很強。有興趣能夠去看這個框架的源碼,很是多值得借鑑的地方。飛狐教你們搭建腳手架,雖然不用這個框架,但不少底層實現也是借鑑的這個框架,好比註解路由。好啦,框架就介紹到這裏啦,後面咱們再慢慢深刻。架構

話很少說,咱們先來個oak例子:

// 引入oak框架
import { Application } from "https://deno.land/x/oak/mod.ts";
// 初始化
const app = new Application();
// 跟koa同樣,運行上下文
app.use((ctx) => { ctx.response.body = "Hello World!"; });
// 監聽端口
await app.listen({ port: 8000 });

在運行的時候,可能會報錯,以下:

image

是否是有點受挫。其實大可沒必要,這個問題是deno版本迭代時std版本未更新至最新引發的。

注意,deno是新玩意兒,有很多坑,官方也在頻繁迭代解決這些坑。 因此,理解萬歲。最簡單的解決辦法只須要把oak的版本升級成最新就行了,以下面的例子。

路由

路由部分oak跟koa不同的是,oak直接提供路由,只需引入便可。以下:

// 升級到oak的最新版本
import { Application, Router } from "https://deno.land/x/oak@v6.0.1/mod.ts";
// 這是官方的例子
const books = new Map<string, any>();
books.set("1", {
  id: "1",
  title: "聽飛狐聊deno",
  author: "飛狐",
});
// 建立路由
const router = new Router();
// 路由,和koa-router的用法同樣
router
  .get("/", (context) => {
    context.response.body = "Hello world!";
  })
  .get("/book", (context) => {
    context.response.body = Array.from(books.values());
  })
  .get("/book/:id", (context) => {
    if (context.params && context.params.id && books.has(context.params.id)) {
      context.response.body = books.get(context.params.id);
    }
  });
const app = new Application();
// 應用路由
app.use(router.routes());
// 容許路中間件引入
app.use(router.allowedMethods());
await app.listen({ port: 8000 });

切記,必定要用最新的版本。一樣的,輸入命令運行。以下圖(postman測試接口):
image

拆分路由

MVC模式你們都不陌生了,咱們這裏僅僅作個簡單的拆分,把路由和控制層獨立出去。 建立一個controller文件夾,在該文件夾下建立一個bookController文件,以下:

// 建立bookController.ts,
// 咱們把數據先移到這來再說
const books = new Map<string, any>();

books.set("1", {
  id: "1",
  title: "聽飛狐聊deno",
  author: "飛狐",
});
// 這裏直接返回一個對象,把路由映射的方法也搬到這裏
export default {
  getbook: ((context: any) => {
    context.response.body = Array.from(books.values());
  }),
  getbookById: ((context: any) => {
    if (context.params && context.params.id && books.has(context.params.id)) {
      context.response.body = books.get(context.params.id);
    }
  })
}

再在根目錄下建立router.ts,代碼以下:

import { Router } from 'https://deno.land/x/oak@v6.0.1/mod.ts';
// 引入控制層的文件
import bookController from './controller/bookController.ts'

const router = new Router();
router
  .get("/", (context) => {
    context.response.body = "Hello world!";
  })
  .get("/book", bookController.getbook)
  .get("/book/:id", bookController.getbookById)

export default router

原來的入口文件server.ts,就變得十分簡潔了,以下:

import { Application } from 'https://deno.land/x/oak@v6.0.1/mod.ts';
import router from './router.ts'

const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

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

這樣就很簡潔了,也利於擴展。好比:

  • 後續用到業務邏輯的時候,咱們能夠再添加service層
  • 後續用到中間件的時候,咱們能夠再添加middleware層
  • 後續擴展異常處理等等

在這個基礎上,在後面的篇章裏咱們再繼續深刻。今天的內容其實已經完成了。這裏再介紹一下,爲啥說這個系列是架構級思想呢?由於咱們在寫代碼的時候,就會基於一些特定的場景考慮,好比微服務等。就像golang裏的go-micro,會集成grpc、etcd、gin等等同樣。有興趣我也能夠寫一套golang系列分享給你們,小弟我有太多想和你們夥兒分享的東東了,好比,TensorFlow.js、Julia量化交易等。呃~好像跑偏了,仍是拉回來先送你們一個結尾彩蛋,爲下一篇打基礎。

彩蛋(改造入口文件)

從如今起,後面的部分咱們要用類class的方式來寫代碼了,先從入口文件開始,改造以下:

// server.ts
import { Application } from 'https://deno.land/x/oak@v6.0.1/mod.ts';
import router from './router.ts'

const app = new Application();
class Server {
  constructor () {
    this.init()
  }

  async init () {
    app.use(router.routes());
    app.use(router.allowedMethods());
    this.listen()
  }

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

new Server()

這裏我不用註釋了,單獨講解一下這個地方,主要三點:

  • 1.建立一個server類,建立一個初始化函數init()
  • 2.在構造函數裏調用初始化函數,把路由,中間件,監聽函數,一切須要初始化執行的函數都拎進去
  • 3.最後運行這個類 這樣作的好處,一個標準化,一個是利於擴展。

下回預告

回顧一下,這篇內容很淺顯,主要是安裝deno,簡單實用oak框架,拆分路由而已。 下回咱們直接聊typescript裝飾器模式,註解,而且實現註解路由。控制層也按照類class的寫法,就跟Java的springmvc同樣,以下圖:

image

從上圖能夠看到,這樣根本就不須要router文件啦。不論是node、deno仍是golang,飛狐真的很不喜歡一個單獨的router文件去維護路由,太麻煩。因此每次搭架子的時候,我必定是先把路由給搞定了,省得麻煩。如今理解爲啥下回直接開幹註解路由了吧,deno的註解路由仍是很一波三折的,由於徹底照搬node會有些坑。期待吧,嘿嘿😜~

相關文章
相關標籤/搜索