前言
本文是基于小满zs的nest教学视频的个人学习笔记,大家感兴趣可以去看看原文 https://xiaoman.blog.csdn.net/article/details/126212760
我们通过axios库发送http请求,首先安装axios
npm i axios -S
然后定义一个控制器 Controller
class Controller {
constructor(){
}
getList(){
}
}
现在我希望Controller的getList()方法可以获取后端API返回的list,同时通过装饰器@GET去发送http请求,getList()方法中不包含任何与网络请求有关的代码。
那么我们要做的第一步,将后端API的URL作为参数传入装饰器函数中,再由装饰器函数发起axios请求,按照正常人想法,既然装饰器本质是一个函数,那我能不能直接将URL作为参数,传入装饰器函数中呢?
const GET:MethodDecorator = (target, key, scriptor, URL:string)=>{
cosnole.log(URL)
}
class Controller{
constructor(){}
@GET("https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10")
getList() {
}
}
可以发现代码报错,MethodDecorator函数类型的参数是固定的,不能随便添加。 因为TS严格约束数据类型,因此通过|来添加参数的方法并不可取,至少这种投机取巧的方式用的多了,项目便很难维护。所以现在,是高阶函数出场的时候了。
既然我们要将URL作为参数传入装饰器函数,但是装饰器函数不能接收新的参数。我们不妨在外面再套一层函数,最外面的一层函数接收URL,然后返回装饰器函数。由于装饰器函数引用了外层函数的URL,形成了一个闭包!我们的问题完美解决了
const GET = (URL: string):MethodDecorator=>{
return (target, key, scriptor)=>{
console.log(URL)
}
}
class Controller{
constructor(){}
@GET("https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10")
getList() {
}
}
这种高阶函数就叫做装饰器工厂,装饰器的本质就是一个高阶函数。
接下来我们就可以继续编写装饰器函数中的逻辑:发送HTTP Get请求,然后将结果返回给装饰的getList()函数
这里我们复习一下方法装饰器函数的三个默认参数
- 原型对象
- 方法名称
- 属性描述符
- 可写:writable
- 可枚举:enumerable
- 可配置:configurable
- ?value:对应的函数
所以我们可以通过descriptor属性描述符的value属性,获取到装饰的函数
import axios from "axios";
const GET = (url: string): MethodDecorator => {
return (target, key, descriptor) => {
//获取到装饰的函数
const fn = descriptor.value as Function;
//自定义参数status,用来传递状态码
let status = 0
//发送get请求
axios.get(url).then(res => {
//如果get请求发送成功,将返回的结果和其他自定义参数传递给getList函数
status = 200
fn(res, status)
}).catch(err => {
status = 500
fn(err, status)
})
}
}
然后我们使用@Get装饰getList方法,然后再getList函数里接收返回的参数。这句话是什么意思呢?我来解释给你听: 我们再axios发起Get请求后,调用了fn()函数,并往里面传递了一系列参数
axios.get(url).then(res => {
//如果get请求发送成功,将返回的结果和其他自定义参数传递给getList函数
status = 200
fn(res, status)
}).catch(err => {
status = 500
fn(err, status)
})
而fn()函数是我们从方法装饰器的属性描述符中获取的
//获取到装饰的函数
const fn = descriptor.value as Function;
结合起来就是,fn()函数接收到的参数,会传递给原方法,即被getList()函数接收
class Controller {
constructor() { }
@GET("https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10")
//注意这里,我定义了两个参数,这两个参数就是从@GET装饰器传来的
getList(res: any, status: number) {
console.log(res.data)
console.log(status)
}
}
这样通过装饰器实现了,将发送HTTP Get请求的逻辑全部集中到@GET返回的装饰器函数,将Get请求返回的结果处理逻辑,全部集中到了getlist()方法中。
总结
我们通过定义装饰器工厂函数(高阶函数),解决了向装饰器传递自定义参数的问题 通过装饰器,成功将发送Get请求逻辑和处理Get请求逻辑分开