2024年最全学习koa源码,弄懂中间件和路由的实现原理,android事件分发面试

最后

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

大厂面试问深度,小厂面试问广度,如果有同学想进大厂深造一定要有一个方向精通的惊艳到面试官,还要平时遇到问题后思考一下问题的本质,找方法解决是一个方面,看到问题本质是另一个方面。还有大家一定要有目标,我在很久之前就想着以后一定要去大厂,然后默默努力,每天看一些大佬们的文章,总是觉得只有再学深入一点才有机会,所以才有恒心一直学下去。

app.use((req, res) => {

res.writeHeader(200)

res.end(‘hello, Moa’)

})

app.listen(3000, () => {

console.log(‘server started at port 3000’)

})

所以我们需要创建一个 moa.js 文件,该文件主要内容是创建一个类 Moa, 主要包含 use() 和 listen() 两个方法

// 创建 moa.js

const http = require(‘http’)

class Moa {

use(callback) {

this.callback = callback

}

listen(…args) {

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

this.callback(req, res)

})

server.listen(…args)

}

}

module.exports = Moa

Context

koa 为了能够简化 API,引入了上下文 context 的概念,将原始的请求对象 req 和响应对象 _res_封装并挂载到了 context 上,并且设置了 getter 和 setter ,从而简化操作

// index.js

// …

// app.use((req, res) => {

//   res.writeHeader(200)

//   res.end(‘hello, Moa’)

// })

app.use(ctx => {

ctx.body = ‘cool moa’

})

// …

为了达到上面代码的效果,我们需要分装 3 个类,分别是 contextrequestresponse , 同时分别创建上述 3 个 js 文件,

// request.js

module.exports = {

get url() {

return this.req.url

}

get method() {

return this.req.method.toLowerCase()

}

}

// response.js

module.exports = {

get body() {

return this._body

}

set body(val) = {

this._body = val

}

}

// context.js

module.exports = {

get url() {

return this.request.url

}

get body() = {

return this.response.body

}

set body(val) {

this.response.body = val

}

get method() {

return this.request.method

}

}

接着我们需要给 Moa 这个类添加一个 createContext(req, res) 的方法, 并在 listen()方法中适当的地方挂载上:

// moa.js

const http = require(‘http’)

const context = require(‘./context’)

const request = require(‘./request’)

const response = require(‘./response’)

class Moa {

// …

listen(…args) {

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

// 创建上下文

const ctx = this.createContext(req, res)

this.callback(ctx)

// 响应

res.end(ctx.body)

})

server.listen(…args)

}

createContext(req, res) {

const ctx = Object.create(context)

ctx.request = Object.create(request)

ctx.response = Object.create(response)

ctx.req = ctx.request.req = req

ctx.res = ctx.response.res = res

}

}

中间件

Koa 中间键机制:Koa 中间件机制就是函数组合的概念,将一组需要顺序执行的函数复合为一个函数,外层函数的参数实际是内层函数的返回值。洋葱圈模型可以形象表示这种机制,是 Koa 源码中的精髓和难点。

洋葱圈模型

同步函数组合

假设有 3 个同步函数:

// compose_test.js

function fn1() {

console.log(‘fn1’)

console.log(‘fn1 end’)

}

function fn2() {

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()

运行结果:

最后

好了,这就是整理的前端从入门到放弃的学习笔记,还有很多没有整理到,我也算是边学边去整理,后续还会慢慢完善,这些相信够你学一阵子了。

做程序员,做前端工程师,真的是一个学习就会有回报的职业,不看出身高低,不看学历强弱,只要你的技术达到应有的水准,就能够得到对应的回报。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

学习从来没有一蹴而就,都是持之以恒的,正所谓活到老学到老,真正懂得学习的人,才不会被这个时代的洪流所淘汰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值