解析Koa2核心原理(手写KOA框架并解析)
前言:
相对于express框架,koa框架只是提供了async/await 的语法应用,大致上逻辑是相同的!
文章主要分为三个部分:
- koa2创建服务
- async/await 语法
- 自己写个koa2
一:koa2
使用koa2创建服务
/**
* koa2 中间件原理
*1. app.use 先将注册的中间件收集起来
*2.实现next。上一个通过next实现触发执行下一个,
* 等await后面的的函数执行完了在执行剩下的语句
*/
const Koa = require('koa');
const app = new Koa();
// 注册中间件
// logger
app.use(async (ctx, next) => {
await next();
console.log('第一个中间件 结束')
});
app.use(async (ctx, next) => {
await next();
console.log('第二个中间件 结束')
});
// response
app.use(async ctx => {
ctx.body = 'Hello World';
console.log('第三个中间件 结束')
});
//监听
app.listen(8000);
通过以上代码可以知道,我们先执行第一个中间件,遇到next呢,然后去执行第二个中间件,等后面的中间件都执行ok后,await解禁,执行第一个中间件的剩下的语句
二: async/await 语法
通常在异步的时候,我们都会使用Promise来,但是了多层的嵌套出现问题,那么如何让异步“同步化”?这里是使用 async/await的语法,当然,返回的是promise对象
/**
* async timeout(){
* return "hello world"
* throw new Error('rejected');
* }
*
* 其 也是函数,所以,直接调用,但是,返回的是promise对象
*timeout() =====>promise
*
* 如果有正确的返回值,那么就调用promise.solve(data)
* 如果返回错误信息, promise.reject(data)
*
* 我们想要在里面执行异步函数读取数据,
* await promise
* 为了防止错误,一般我们会try catch 包裹
*/
三:自己写KOA2框架
const http = require('http');
class IKoa {
constructor() {
this.middlewareList = [];
}
/**
* 收集 async中间件
*/
use(fn){
this.middlewareList.push(fn)
}
//创建上下文,组合相关的请求来和去的数据
createContext(req,res){
const ctx ={
req,
res
}
ctx.body = (data) => {
let _d = data;
if(typeof _d != 'string'){
_d = JSON.stringify(_d)
}
res.end(_d)
}
return ctx;
}
//组合中间件,定义next方法
compose(middlewareList){
return function(ctx){
// ctx.body({
// name:"a"
// })
function next(i) {
//取出一个中间件
const fn = middlewareList[i]
if(fn){
//next.bind(null,i+1) = = next() 执行下一个中间件
//这里也就是执行中间件函数 dispatch相当于next
fn(ctx, next.bind(null, i + 1)) // promise
}
}
//先执行第一个
return next(0)
}
}
/**
* 上下文
* @param {[type]} ctx
* @param {Function} fn 第一个中间件
* @return fn 这里返回一个fn
*/
handleRequest(ctx,fn){
return fn(ctx)
}
callback(){
//获取第一个中间件
const fn = this.compose(this.middlewareList)
return (req,res) => {
const ctx = this.createContext(req,res);
//这里返回第一个中间件,作为callback的返回
return this.handleRequest(ctx,fn)
}
}
listen(...agrus){
//这里的核心,callback 返回是执行的第一个中间件,通过第一个中间件去next下一个中间件
const server = http.createServer(this.callback());
server.listen(...agrus)
}
}
module.exports = IKoa
通过以上代码,可以看出,callback返回的是第一个中间件的函数的组装函数,在这个组装函数里面先执行自身,其参数是ctx上下文,和下一个中间件函数,其实next也就是下一个中间件函数,那么执行next就相当于执行下一个中间件,当然,返回的是Promise,那么就可以用await接收
测试使用:
const Koa = require('./i-koa');
const app = new Koa();
app.use( async (ctx, next) => {
// ctx.body("111")
next()
console.log("111");
})
app.use( async (ctx, next) => {
ctx.body("222")
})
app.listen(9000,()=>{
console.log("启动了");
})
网友评论