egg.js路由的优雅改造

在使用express,koa, 或者是egg.js进行node server开发的过程中,我们的路由基本上都是定义在controller层的,框架对于 node 原生路由都会进行一层封装,一版都会封装到一个router对象,提供http的method对应的方法,然后在回调函数的入参中封装请求对象和响应对象。

//koa 中koa-router中的router.js router.get('/home',async (ctx:{req,res},next)=>{ let reqParams = req.query; res.body = {a:1} }) //egg.js app/router.js module.exports = app => { const { router, controller } = app; router.get('/user/:id', controller.user.info); };

类似上边为koa-router和egg.js中设置的路由。路由的设置并不是特别明显直观。这次的路由改造示例,是使用egg.js来进行尝试,改造后的形式如下:

//改造后的controller @prefix('/page') export default class PageController extends Controller { @get('/example') public async index():Promise<void> { const {ctx} = this; ctx.body={a:1}; ctx.status = 200; } }

在进行改造的过程中,是在TypeScript环境中使用Decorator+Reflect-metadata来对egg.js的controller进行改造,主要需要了解的概念有:Decorator,注解,Reflect,元数据等基本概念。

Decorator 装饰器

decorator即是装饰器,在不侵入类的原有代码的情况下在编译时给类添加行为或者修改行为的表现。目前还在es7草案阶段,js中使用还需要babel装嘛,但是在 TypeScript 目前通过配置tsconfig可以使用decorator。

先来简单看下decorator作用在类和类的方法上的简单用法

//类的修饰 @setHelloDecorator class oneClass {} function setHelloDecorator(target){ target.hello = true; } //类的方法的修饰 class towClass { @nonenumerable someMethod(){} } function nonenumerable(target, key, descriptor){ //target 修饰方法的类的原型对象 //key 修饰方法名 //descriptor 修饰方法的描述对象 descriptor.writable = false; }

在TypeScript的源码中可以找到支持Decorator类型的定义:

declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void; declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void; declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void; declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, parameterIndex: number) => void;

可以看到decorator可以用来修饰class,property,method,parameter。

元数据 Metadata

元数据简单理解起来就是,修饰数据的数据,比如说的身材,身材魁梧,身材苗条,这里身材为元数据的项目,魁梧/苗条为元数据的内容。一个人的描述正是由众多的元数据组成的,(长相,身高,年龄,学历等等数据)

Annotation 注解

之前我对于注解和装饰器的概念经常搞混,现在知道这是两个不同的概念:

注解 仅提供附加元数据支持,并不能实现任何操作。

装饰器 仅提供定义劫持,能够对类及其方法的定义但是没有提供任何附加元数据的功能。

所以对于decorator来言,是无法直接进行元数据的操作的,想要对元数据进行操作,还需要借助于比如Object或者Reflect-metadata来实现

JavaScript中需要反射Reflect

反射这个名词是用于描述能够检查同一系统中的其他代码的代码,程序在运行时能够获取自身的信息。

当然我们也可以使用for...in或者是Object.getOwnPropertyDescriptor等来反射获取某个类或者类属性的信息。但是原有的各种方法调用方式较为复杂。

ES6中已经有了一个Reflect对象,在MDN中的定义为:

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与处理器对象的方法相同。Reflect不是一个函数对象,因此它是不可构造的。你不能将其与一个new运算符一起使用,或者将Reflect对象作为一个函数来调用。Reflect的所有属性和方法都是静态的(就像Math对象)。

Reflect对象的设计目的有:

将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上

修改某些Object方法的返回结果,让其变得更合理。

让Object操作都变成函数行为。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为。

Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。

Reflect对象能够将实现反射机制的方法都汇总于一个地方,并且用法上更简单。让我们操作Object时更加方便简洁。

Reflect Metadata

ES6提供的Refelct并不满足修改元数据,我们要额外引入一个库reflect-metadata。并且Decorator中也无法进行元数据的获取和修改。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjfyp.html