koa主要做的就是api优雅化以及它的洋葱圈模型
首先根据我们使用koa时,我们会先new 一个实例然后use注册事件,listen去监视端口,所以我们可以先写一个如下的类
const http = require('http')
class MyKoa {
use(callback){
this.callback = callback
}
listen(...args){
const server = http.createServe((req,res) => {
this.callback()
})
server.listen(...args)
}
}
将req,res挂载在ctx上
将之前http的api优雅化
这边没有跟vue里通过递归对象然后object.defineProperty实现主要原因是因为他的属性是固定的,不像vue里data的属性值是不固定的
//context.js
module.exports = {
get body(){
return this.res.body
}
set body(val){
this.res.body = val
}
get url(){
return this.req.url
}
get method(){
return this.res.method
}
......
}
//request.js
module.exports = {
get method(){
return this.request.method
}
set methods(val){
this.request.method = val.toUpperCase()
}
get url(){
return this.request.url
}
.....
}
//response.js
module.exports = {
get body(){
return this.response._body
}
set body(val){
this.response._body = val
}
.....
}
用Object.create创建对象
因为需要将http里的res和req 传入进行对象继承,由于{...obj}运算符只能将对象进行浅拷贝,JSON.parse(JSON.stringify(obj))会深拷贝,但是无法继承源对象里的get,set方法,所以这边用object.create(obj)进行创建。
| 浅拷贝 | 深拷贝 | get set方法 | |
|---|---|---|---|
| 结构赋值 | √ | ||
| JSON.parse(JSON.stringify) | √ | √ | |
| Object.create | √ | √ |
const http = require('http')
const request = require('./request.js')
const response = require('./response.js')
const conext = require('./context.js')
class MyKoa {
use(callback){
this.callback = callback
}
listen(...args){
const server = http.createServe((req,res) => {
const ctx = this.createContext(req,res)
this.callback()
})
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.req = res
return ctx
}
}
洋葱圈模型的实现
实现聚合函数处理中间件
async function f1(next){
console.log(1)
await next()
console.log('我执行完啦 f1')
}
async function f2(next){
console.log(2)
await delay(2000)
await next()
console.log('我执行完啦 f2')
}
async function f3(next){
console.log(3)
await next()
}
function delay(time){
return new Promise((resolve) => {
setTimeout(() => resolve(),time)
})
}
//聚合函数
function compose(middleware){
return function(){
return dispatch(0)
function dispatch(i){
const fn = middleware[i]
if(!fn) return Promise.resolve() //当不是函数时候不能直接结束要返回个promise
return Promise.resolve(fn(function next(){
return dispatch(i+1)
}))//next函数本质就是下一个要执行的函数
}
}
}
将copmose函数应用在koa里
const http = require('http')
const request = require('./request.js')
const response = require('./response.js')
const context = require('./context.js')
class MyKoa{
constructor(){
this.middleWares = []
}
use(middleWare){
this.middleWares.push(middleWare)
}
listen(...args){
const server = http.createServer(async(req,res) => {
const ctx = this.createContext(req,res) //将req,res挂载在ctx
const fn = this.compose(this.middleWares)
await fn(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
return ctx
}
compose(middleware){
return function(ctx){
return dispatch(0)
function dispatch(i){
const fn = middleware[i]
if(!fn) return Promise.resolve() //当不是函数时候不能直接结束要返回个promise
return Promise.resolve(fn(ctx,function next(){
return dispatch(i+1)
}))//next函数本质就是下一个要执行的函数
}
}
}
}
module.exports = MyKoa