大家好,小弟飞狐。好久没来思否了,再来带来了的肯定是干货。从Deno开始,飞狐带来的相对到目前为止前所未有的Deno系列。话不多说,用技术谈话。

你学不动的 Deno 来了

还记得 Github 上那个让人学不动的 Deno 么?就在2020年5月13日,Deno1.0正式公布。作为新晋网红运行时,Deno真的会代替 Node 吗?这个问题能够追溯到2018年,从Node之父 Ryan Dahl的演讲说起,Ryan在演讲中谈及对Node有十大不满之处,并且在演讲的最初颁布了Deno我的项目。我在这里只列三大新个性。

  • 首先,Deno 作为一个JavaScript/TypeScript 运行时,底层基于性能超高的 Rust 编写,在性能和存储平安上有先天的劣势。
  • 其次,Deno 领有残缺的规范库,不再有 NPM 或 node_modules 文件夹,容许从任何中央导入所需模块。
  • 另外,Deno 集成 TypeScript,不再像以前一样借助工具编译,而是通过外部转换。不过仿佛又要剥离。

综上所述,你会发现,Deno真的是青出于蓝而胜于蓝。是否代替,只是工夫问题而已。我也看到很多人在做deno和node的性能比拟,但在目前我认为做这两者的性能比拟齐全没有必要。

装置

咱们一开始甭管deno底层用的go还是rust,为啥要从go换成rust、或者是deno的技术架构是咋样?这些目前都不要关怀,咱们就把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
  • Homebrew (Mac): brew install deno
  • Chocolatey (Windows): choco install deno
  • Scoop (Windows): scoop install deno

第一个例子也是来自官网,每一行我都加了解释。如下:

// 创立文件 /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根底的同学间接动手。

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

而后在浏览器关上http://localhost:8000,就能够看到hello world了,如下图:

框架之选

家喻户晓,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 });

在运行的时候,可能会报错,如下:

是不是有点受挫。其实大可不必,这个问题是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测试接口):

拆分路由

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.tsimport { 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一样,如下图:

从上图能够看到,这样基本就不须要router文件啦。不论是node、deno还是golang,飞狐真的很不喜爱一个独自的router文件去保护路由,太麻烦。所以每次搭架子的时候,我肯定是先把路由给搞定了,省得麻烦。当初了解为啥下回间接开干注解路由了吧,deno的注解路由还是很一波三折的,因为齐全照搬node会有些坑。期待吧,嘿嘿????~