如何从头实现一个node.js的koa框架

2020-06-17 06:09:13易采站长站整理


let next1 = async function () {
await m3();
}
m2(next1);
// 输出:m2,m3

进一步,考虑从m1开始执行,那么,m1的next参数需要是一个执行m2的函数,并且给m2传入的参数是m3,下面来模拟:


let next1 = async function () {
await m3();
}
let next2 = async function () {
await m2(next1);
}
m1(next2);
// 输出:m1,m2,m3

那么对于n个async函数,希望他们按顺序依次执行呢?可以看到,产生nextn的过程能够抽象为一个函数:


function createNext(middleware, oldNext) {
return async function () {
await middleware(oldNext);
}
}
let next1 = createNext(m3, null);
let next2 = createNext(m2, next1);
let next3 = createNext(m1, next2);
next3();
// 输出m1, m2, m3

进一步精简:


let middlewares = [m1, m2, m3];
let len = middlewares.length;
// 最后一个中间件的next设置为一个立即resolve的promise函数
let next = async function () {
return Promise.resolve();
}
for (let i = len - 1; i >= 0; i--) {
next = createNext(middlewares[i], next);
}
next();
// 输出m1, m2, m3

至此,我们也有了koa中间件机制实现的思路,新的application.js如下:


/**
* @file simpleKoa application对象
*/
let http = require('http');
let context = require('./context');
let request = require('./request');
let response = require('.//response');
class Application {
/**
* 构造函数
*/
constructor() {
this.middlewares = [];
this.context = context;
this.request = request;
this.response = response;
}
// ...省略中间
/**
* 中间件挂载
* @param {Function} middleware 中间件函数
*/
use(middleware) {
this.middlewares.push(middleware);
}
/**
* 中间件合并方法,将中间件数组合并为一个中间件
* @return {Function}
*/
compose() {
// 将middlewares合并为一个函数,该函数接收一个ctx对象
return async ctx => {
function createNext(middleware, oldNext) {
return async () => {
await middleware(ctx, oldNext);
}
}
let len = this.middlewares.length;
let next = async () => {
return Promise.resolve();
};
for (let i = len - 1; i >= 0; i--) {
let currentMiddleware = this.middlewares[i];
next = createNext(currentMiddleware, next);
}
await next();
};
}
/**
* 获取http server所需的callback函数
* @return {Function} fn
*/
callback() {
return (req, res) => {
let ctx = this.createContext(req, res);
let respond = () => this.responseBody(ctx);