学习koa源码,弄懂中间件和路由的实现原理,前端面试题2024

本文介绍了如何在Node.js中实现同步和异步函数的组合,重点围绕compose函数,以及如何将其应用到Koa框架的中间件中,包括处理异步流程和实现简单的路由功能。
摘要由CSDN通过智能技术生成

console.log(‘fn2’)

console.log(‘fn2 end’)

}

function fn3() {

console.log(‘fn3’)

console.log(‘fn3 end’)

}

我们如果想把三个函数组合成一个函数且按照顺序来执行,那通常的做法是这样的:

// compose_test.js

// …

fn3(fn2(fn1()))

执行 node compose_test.js 输出结果:

fn1

fn1 end

fn2

fn2 end

fn3

fn3 end

当然这不能叫做是函数组合,我们期望的应该是需要一个 compose() 方法来帮我们进行函数组合,按如下形式来编写代码:

// compose_test.js

// …

const middlewares = [fn1, fn2, fn3]

const finalFn = compose(middlewares)

finalFn()

让我们来实现一下 compose() 函数,

// compose_test.js

// …

const compose = (middlewares) => () => {

[first, …others] = middlewares

let ret = first()

others.forEach(fn => {

ret = fn(ret)

})

return ret

}

const middlewares = [fn1, fn2, fn3]

const finalFn = compose(middlewares)

finalFn()

可以看到我们最终得到了期望的输出结果:

fn1

fn1 end

fn2

fn2 end

fn3

fn3 end

异步函数组合

了解了同步的函数组合后,我们在中间件中的实际场景其实都是异步的,所以我们接着来研究下异步函数组合是如何进行的,首先我们改造一下刚才的同步函数,使他们变成异步函数,

// compose_test.js

async function fn1(next) {

console.log(‘fn1’)

next && await next()

console.log(‘fn1 end’)

}

async function fn2(next) {

console.log(‘fn2’)

next && await next()

console.log(‘fn2 end’)

}

async function fn3(next) {

console.log(‘fn3’)

next && await next()

console.log(‘fn3 end’)

}

//…

现在我们期望的输出结果是这样的:

fn1

fn2

fn3

fn3 end

fn2 end

fn1 end

同时我们希望编写代码的方式也不要改变,

// compose_test.js

// …

const middlewares = [fn1, fn2, fn3]

const finalFn = compose(middlewares)

finalFn()

所以我们只需要改造一下 compose() 函数,使他支持异步函数就即可:

// compose_test.js

// …

function compose(middlewares) {

return function () {

return dispatch(0)

function dispatch(i) {

let fn = middlewares[i]

if (!fn) {

return Promise.resolve()

}

return Promise.resolve(

fn(function next() {

return dispatch(i + 1)

})

)

}

}

}

const middlewares = [fn1, fn2, fn3]

const finalFn = compose(middlewares)

finalFn()

运行结果:

fn1

fn2

fn3

fn3 end

fn2 end

fn1 end

完美!!!

完善 Moa

我们直接把刚才的异步合成代码移植到 moa.js 中, 由于 koa 中还需要用到 ctx 字段,所以我们还要对 compose() 方法进行一些改造才能使用:

// moa.js

// …

class Moa {

// …

compose(middlewares) {

return function (ctx) {

return dispatch(0)

function dispatch(i) {

let fn = middlewares[i]

if (!fn) {

return Promise.resolve()

}

return Promise.resolve(

fn(ctx, function () {

return dispatch(i + 1)

})

)

}

}

}

}

实现完 compose() 方法之后我们继续完善我们的代码,首先我们需要给类在构造的时候,添加一个 middlewares,用来记录所有需要进行组合的函数,接着在use() 方法中把我们每一次调用的回调都记录一下,保存到middlewares 中,最后再在合适的地方调用即可:

// moa.js

// …

class Moa {

constructor() {

this.middlewares = []

}

use(middleware) {

this.middlewares.push(middleware)

}

listen(…args) {

const server = http.createServer(async (req, res) => {

// 创建上下文

const ctx = this.createContext(req, res)

const fn = this.compose(this.middlewares)

await fn(ctx)

// 响应

res.end(ctx.body)

})

server.listen(…args)

}

// …

}

我们加一小段代码测试一下:

// index.js

//…

const delay = () => new Promise(resolve => setTimeout(() => resolve()

, 2000))

app.use(async (ctx, next) => {

ctx.body = “1”

await next()

ctx.body += “5”

})

app.use(async (ctx, next) => {

ctx.body += “2”

await delay()

await next()

ctx.body += “4”

})

app.use(async (ctx, next) => {

ctx.body += “3”

})

运行命令 node index.js 启动服务器后,我们访问页面 localhost:3000 查看一下,发现页面显示 12345 !

到此,我们简版的 Koa 就已经完成实现了。让我们庆祝一下先!!!

Router

Koa 还有一个很重要的路由功能,感觉缺少路由就缺少了他的完整性,所以我们简单介绍下如何实现路由功能。

其实,路由的原理就是根据地址和方法,调用相对应的函数即可,其核心就是要利用一张表,记录下注册的路由和方法,原理图如下所示:

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
img

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-qk9CwOka-1710925373926)]
[外链图片转存中…(img-p3tylDeu-1710925373927)]
[外链图片转存中…(img-7i0J4t0A-1710925373927)]
[外链图片转存中…(img-RolybqYX-1710925373928)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
[外链图片转存中…(img-nm6LdLpc-1710925373928)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值