博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从 JavaScript 到 TypeScript 5 - 路由进化
阅读量:5983 次
发布时间:2019-06-20

本文共 3331 字,大约阅读时间需要 11 分钟。

随着应用的庞大,项目中 JavaScript 的代码也会越来越臃肿,这时候许多 JavaScript 的语言弊端就会愈发明显,而 TypeScript 的出现,就是着力于解决 JavaScript 语言天生的弱势:静态类型。

前端开发 QQ 群:377786580

这篇文章首发于我的个人博客 《》,系列目录:

  • 《》
  • 《》
  • 《》
  • 《》
  • 《从 JavaScript 到 TypeScript 5 - express 路由进化》
  • 《》

在上一篇文章 《》 我们介绍了装饰器和反射,在这篇文章中,我们会把这两个特性引入,并且在 上,实现一层全新的路由封装。

express 路由

首先我们来看一个简单的 express 路由 (router):

// 对网站首页的访问返回 "Hello World!"app.get('/', function (req: Request, res: Reponse) {  res.send('Hello World!')})app.post('/user', function (req: Request, res: Reponse) {  res.send(`User Id ${req.query.id}`)})

在上面的路由代码我们演示了一个普通流水线式的路由。

基于上一篇文章中我们学到的装饰器和反射的知识,我们将要实现 路由的配置通过装饰器实现,并且实现一层路由逻辑的封装。

路由进化

基于装饰器和反射,我们要实现的路由最终效果是这样的:

class Home {  @path('/user')  @httpGet  user (id: string) {    return `User Id ${id}`  }}
GET  HTTP/1.1Host: /user?id=tasaid.com

这段代码相比传统的路由配置,优点如下:

  • 将路由的配置抽离成为了装饰器,让整个 router 函数内部只需要处理业务逻辑即可,路由配置简单明了
  • 隐藏 reqres,每个 router 直接返回结果即可,无需自己再输出结果

装饰器: HTTP Method

我们先编写 HTTP Method 的装饰器,我们将实现两个装饰器,分别叫做 httpGethttpPost,对应 HTTP Method 的 GET/POST

原理上,我们会将 router 配置的数据都挂到使用装饰器的方法上。

import 'reflect-metadata'export const symbolHttpMethodsKey = Symbol("router:httpMethod")export const httpGet = function (target: any, propertyKey: string) {  // 挂载到调用装饰器的方法上  Reflect.defineMetadata(symbolHttpMethodsKey, 'get', target, propertyKey)}export const httpPost = function (target: any, propertyKey: string) {  Reflect.defineMetadata(symbolHttpMethodsKey, 'post', target, propertyKey)}

装饰器: path

有了上面 HTTP Method 装饰器的实现,我们再实现 path 装饰器将会很简单。

当然,我们还可以在 path 中实现对原方法的封装:隐藏 reqres,并对 router 的输出结果进行封装。

注意这里使用的是装饰器工厂:

import 'reflect-metadata'export const symbolPathKey = Symbol.for('router:path')export let path = (path: string): Function => {  return function (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor
) { Reflect.defineMetadata(symbolPathKey, path, target, propertyKey) if (!descriptor.value) return // 覆盖掉原来的 router method,在外层做封装 let oldMethod = descriptor.value descriptor.value = function (req: Request, res: Response) { const params = Object.assign({}, req.body, req.query) let methodResult = oldMethod.call(this, params) // 输出返回结果 res.send(methodResult) } }}

Router? Controller!

现在,我们需要将所有的 Router 按照自己的业务规则/或者自定义的其他规则进行归类 —— 然后提取出对应的 Class,例如下面的 User Class 就是把用户信息所有的 router 都归类在一起:

class User {  @httpPost  @path('/user/login')  login() { }  @httpGet  @path('/user/exit')  exit() { }}

然后在 express 配置的入口逻辑那里,把 class 对应的方法遍历一遍,然后使用 reflect-metadata 反射对应的 router 配置即可:

import 'reflect-metadata'// 装饰器挂载数据的 keyimport { symbolHttpMethodsKey, symbolPathKey } from './decorators'const createController = (app: Express) => {  let user = new User()  for (let methodName in user) {    let method = user[methodName]    if (typeof method !== 'function') break    // 反射得到挂载的数据    let httpMethod = Reflect.getMetadata(symbolHttpMethodsKey, user, methodName)    let path = Reflect.getMetadata(symbolPathKey, user, methodName)    // app.get('/', () => any)    app[httpMethod](path, method)  }}

至此,我们的 express 路由进化完毕,效果如下:

clipboard.png

完整的例子可以参考我的 。

结语

装饰器目前在 ECMAScript 新提案中的 ,由于装饰器在其他语言中早已实现,例如 Java 的注解(Annotation) 和 C# 的特性(Attribute),所以纳入 ECMAScript 规范只是时间问题了。

装饰器来装饰路由,并且封装 router 操作的的思路缘起 .NET MVC 架构:

clipboard.png

angular 2.x 使用也引入了装饰器作为核心开发,随着规范的推进,相信装饰器进入大家视野,应用的场景也会越来越多。

在下一篇文章 《》 中,我们将介绍如何在 Vue 中引入 TypeScript。

 

TypeScript 中文网:

TypeScript 视频教程:《》

转载地址:http://vqrox.baihongyu.com/

你可能感兴趣的文章
使用MapReduce实现一些经典的案例
查看>>
5 . 4 . 3 架构
查看>>
类静态和实例化执行顺序优先级(静态构造函数、静态变量、静态方法)
查看>>
ajax提交param 后台接受是对象
查看>>
ajax基础一
查看>>
http://cuiqingcai.com/993.html
查看>>
【NOI2018模拟5】三角剖分Bsh
查看>>
redis安装使用
查看>>
【干货】Java岗面试考点大合集
查看>>
Android安全开发之浅谈密钥硬编码
查看>>
iOS 计算两个日期字符串的差值
查看>>
UTF-8 编码及检查其完整性
查看>>
由一条微博引发的 — Xcode LLDB 调试断点总结
查看>>
Android NDK开发扫盲及最新CMake的编译使用
查看>>
Weex开发系列(一):初识Weex
查看>>
开源 UI 库中,唯一同时实现了大表格虚拟化和树表格的 Table 组件
查看>>
找到思聪王
查看>>
[译] 学习 Spring Security(五):重发验证邮件
查看>>
快速的React Native开发方法
查看>>
Spring核心系列之AOP(一)
查看>>