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