这份Koa的简易Router手敲指南请收下
上一期链接——也就是本文的基础,参考KOA,5步手写一款粗糙的web框架
本文参考仓库:点我
Router其实就是路径匹配,通过匹配路径,返回给用户相应的网站内容。
以下方例子为例,主要通过提取req中的path信息,来匹配当前路径,并给ctx.body赋值,返回相应的界面。这个过程不复杂,就是一个匹配路径的过程。但是这种会不会太臃肿了呢,而且很有可能路径一多,就要被if...else...给弄晕了。
app.use((ctx,next)=>{
   //简易路由
   let {path}=ctx
   if(path==="/"){
       ctx.body="index"
   }else if(path==="/admin"){
        ctx.body="admin"
   }else if(path==="/user"){
        ctx.body="user"
   }
})
这个时候专门处理路径的插件就出现了,写一个Router,专门用来管理路径。
Router的功能一共是两个:
- 匹配路径
 - 返回相应页面
 
如果Router要挂载到app上,那么语法是这样的app.use(router.routes()),也就是说:
- Router本身就是个中间件
 - 为了返回匹配的路由,写一个中间件挂到
app上 
了解了Router的大概,我们开始一步步动手写Router吧!
STEP1 创建Router
先把Router的框架写好,一个构造器,一个get方法用于配置路由,一个routers变成路由匹配的中间件挂在到app上。
class Router{
    constructor(){}
    get(path,callback){}
    routers(){}
}
我们获取路由的时候,一定会配置页面,那么这个页面的类也要加上了,每次get的时候,就加入一个页面到数组中。
class Page{
    constructor(path,callback){
        this.path=path
        this.callback=callback
    }
}
class Router{
    constructor(){
        this.pages=[]
    }
    get(path,callback){
        this.pages.push(new Page(path,callback))
    }
    routers(){}
}
因为路由是对中间件的封装,所以用法上是和app.use类似的:
router.get(path,(ctx,next){
    ctx.body='xxx'
    next()
})
是不是很眼熟?这个get中的callback参数就是中间件。
STEP2 写一个中间件,返回匹配路由的中间件
routers就干三件事:
- 筛选出匹配的路由,
array.filter就可以做到 - 组合执行这些路由
 - 返回一个中间件
 
compose(ctx,next,routers){
    function dispatch(index){
        if(index===routers.length) return next();
        let router=routers[index]
        router(ctx,()=>dispatch(index+1));
    }
    dispatch(0)
}
routers(){
    let dispatch = (ctx,next)=>{
        let path=ctx.path
        let routers=this.pages.filter(p=>{console.log(p.path);return p.path===path}).map(p=>p.callback)
        this.compose(ctx,next,routers)
    }
    return dispatch
}
大家有没有很眼熟,和koa中的application.js的回调很像。其实就是一个回调的过程,封装之后,便于我们使用。
STEP3 给路由分个组吧
我们再写路由的时候,如果全部写全路径,感觉会很啰嗦:
router.get("/admin",(ctx,next)=>{})
router.get("/admin/login",(ctx,next)=>{})
router.get("/admin/register",(ctx,next)=>{})
...
router.get("/user",(ctx,next)=>{})
router.get("/user/login",(ctx,next)=>{})
router.get("/user/register",(ctx,next)=>{})
....
我们给路由分组,其实思路很简单,就是给每个小路由新建一个Router,然后大路由用use方法,将这些路由集合到一起。
let admin=new Router()
admin.get("/",(ctx,next)=>{
    ctx.body="admin"
    next()
})
let user=new Router()
user.get("/",(ctx,next)=>{
    ctx.body="user"
    next()
})
//链式调用~
let router=new Router()
router.use("/admin",admin.routers())
.use("/user",user.routers())
app.use(router.routers())
那么问题来了,use要怎么写呢才能组合这些routers??我们先来分析下use的功能:
- 组合路径
 - 将route加入当前对象的数组中
 
use中有两个参数一个path,一个router.routers()的中间件,可是我们需要router数组对象,所以我们可以这么做:
routers(){
    let dispatch = (ctx,next)=>{
      .....
    }
    dispatch.router=this
    return dispatch
}
在中间件上暗搓搓地加一个router的对象,将自己一起传递出去,有么有很机智
有了router的数组对象,那么use这个方法就很好实现了,将page循环一波,加入当前对象的pages,就好了。这里再将自己返回,然后就可以愉快地使用链式调用了。
 use(path,middleware) {
    let router = this;
    middleware.router.pages.forEach(p => {
        router.get(path+p.path,p.callback)
    });
    return router
}
step4 LAST BUT NOT LEAST
大家需要注意,还记得上一期讲的async/await异步吗?
如果有任何除了路由的操作都要放在路由上方执行,因为路由只是匹配路径,返回结果,并没有async/await操作。
所以一定注意:
这样是有效的·,页面返回aaa
app.use(async (ctx,next)=>{
    await makeAPromise(ctx).then(()=>{next()})
})
...
app.use(router.routers())
这样是无效的,页面不会返回aaa
...
app.use(router.routers())
app.use(async(ctx,next)=>{
    await next()//等待下方完成后再继续执行
    ctx.body="aaa"
})
												
											这份Koa的简易Router手敲指南请收下的更多相关文章
- 干货 | 请收下这份2018学习清单:150个最好的机器学习,NLP和Python教程
		
机器学习的发展可以追溯到1959年,有着丰富的历史.这个领域也正在以前所未有的速度进化.在之前的一篇文章中,我们讨论过为什么通用人工智能领域即将要爆发.有兴趣入坑ML的小伙伴不要拖延了,时不我待! 在 ...
 - JAVA工程师必学技能,进阶&涨薪的推进器!这份实战教程请收下
		
Netty 作为互联网中间件的基石,是 JAVA 工程师进阶为高级程序员必备的能力之一.也是目前是互联网中间件领域使用最广泛最核心的网络通信框架. Netty是一个高性能.异步事件驱动的NIO框架,它 ...
 - 爬虫需要登陆怎么办?这份python登陆代码请收下
		
模拟登陆思路 通过selenium中的webdriver控制浏览器登录目标网站,然后获取模拟登陆需要的Cookie,再利用此Cookie来达到登录的效果.本次我们使用webdriver来驱动火狐浏览器 ...
 - 购买二手iPhone需要注意什么?这份避坑指南请收好!
		
iPhone二手机市场一直非常火热,有时甚至出现供不应求的情况.主要是因为新机的价格不便宜,没什么性价比,很多小伙伴会选择低价购买二手iPhone,价格基本只要新机的二到五折.不过二手机的水深相信大家 ...
 - KOA的简易模板引擎实现方式
		
上上一期链接--也就是本文的基础,参考KOA,5步手写一款粗糙的web框架 上一期链接--有关Router的实现思路,这份Koa的简易Router手敲指南请收下 本文参考仓库:点我 上一期科普了Rou ...
 - 参考KOA,5步手写一款粗糙的web框架
		
我经常在网上看到类似于KOA VS express的文章,大家都在讨论哪一个好,哪一个更好.作为小白,我真心看不出他两who更胜一筹.我只知道,我只会跟着官方文档的start做一个DEMO,然后我就会 ...
 - 从DeepNet到HRNet,这有一份深度学习“人体姿势估计”全指南
		
从DeepNet到HRNet,这有一份深度学习"人体姿势估计"全指南 几十年来,人体姿态估计(Human Pose estimation)在计算机视觉界备受关注.它是理解图像和视频 ...
 - 毕业季offer怎么拿?收下这份非典型求职面试指南
		
摘要:求职面试莫慌,先自我评估一下 ,华为云专家手把手为你指导. 本文分享自华为云社区<毕业季offer怎么拿?收下这份非典型求职面试指南>,原文作者:技术火炬手 . 又是一年毕业季,对于 ...
 - GitHub 上一份很受欢迎的前端代码优化指南
		
http://segmentfault.com/a/1190000002587334?utm_source=weekly&utm_medium=email&utm_campaign=e ...
 
随机推荐
- c#实现播放器的集中方式
			
http://www.cnblogs.com/iskyoole/archive/2012/03/25/2417181.html(原文链接地址) 一.使用vs自带的windows media play控 ...
 - 【bzoj2282】[Sdoi2011]消防
			
两次bfs可得直径,答案一定不会小于所有点到直径的距离最大值,只要把直径上的边权设为0,任选直径上一点bfs可得将最大值作为二分下界,二分直径左右端点的舍弃部分 #include<algorit ...
 - ffmpeg resize and scale
			
ffmpeg缩小视频尺寸 | 楚盟博客 https://www.5yun.org/13126.html ffmpeg -i test.mp4 -s 480×360 out.mp4 常用分辨率: 108 ...
 - Message: SyntaxError: unterminated string literal
			
#Message: SyntaxError: unterminated string literalmytxt = words.replace('\n','').replace('\r','') js ...
 - Explicit Interface Implementation (C# Programming Guide)
			
https://msdn.microsoft.com/en-us/library/ms173157.aspx If a class implements two interfaces that con ...
 - [Jsoi2015]字符串树
			
https://www.zybuluo.com/ysner/note/1298148 题面 字符串树本质上还是一棵树,即\(N\)个节点\(N-1\)条边的连通无向无环图,节点 从\(1\)到\(N\ ...
 - bzoj4237 稻草人——分治
			
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4237 分治: 先把所有点按 y 排序,然后二分递归: 对于每个 mid ,计算经过它的矩形的 ...
 - bzoj2705 [SDOI2012]Longge的问题——因数
			
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2705 一开始自己想了半天... 有了点思路:遍历 n 的因数 k,每个因数要预处理出 gcd ...
 - 慕课网2-5 编程练习:通过jQuery通配符选择器进行文字变色
			
2-5 编程练习 请请使用*选择器将div标签中的字体颜色变成红色 效果图: 任务 (1)使用通配符选择器 (2)使用jQuery的.css()方法设置样式,语法css('属性 '属性值') 参考代码 ...
 - INT类型知多少
			
前言: 整型是MySQL中最常用的字段类型之一,通常用于存储整数,其中int是整型中最常用的,对于int类型你是否真正了解呢?本文会带你熟悉int类型相关知识,也会介绍其他整型字段的使用. 1.整型分 ...