Koa2 实现原理
在 Koa 对象中存储只存储中间对应的方法,使用 use() 方法向队列中添加中间件对象
next 方法是一个有名的立即执行函数,当第一次匹配时会立即执行,使用函数对象的 bind() 方法进行参数绑定,并将包装后的 ctx 参数和该函数传递给用户中间件的方法为参数,若用户调用 next 方法时会调用我们定义好的 next 方法执行下一个中间件方法
将中间件函数的执行结果使用 promise 包装,兼容非 async 函数的中间件
const http = require("http");
/**
* 将请求对象和响应对象包装成ctx对象
* @param {Request} req 请求对象
* @param {Response} res 响应对象
*/
function extendsMethod(req, res) {
return {
req,
res
};
}
class Koa {
constructor() {
this.middlewares = []; //用于存放中间件方法
}
use(...args) {
this.middlewares.push(...args); //添加到中间件队列
return this; //链式调用
}
listen(...args) {
const server = http.createServer((req, res) => {
const ctx = extendsMethod(req, res); //包装成ctx对象
const middlewares = this.middlewares; //暂存中间件队列
//由于中间件队列是地址引用,所以不能使用出队方式,否则下次访问时就没了
(function next(i) {
const middleware = middlewares[i]; //取出第i个中间件
if (!middleware) return; //若取出的是null,说明后面已经没有中间件了,所以什么也不用做
try {
return Promise.resolve(middleware(ctx, next.bind(null, i + 1)));
//兼容非async函数,包装成promise
//next.bind(null, i + 1)返回一个参数为i + 1的next函数,用于递归向下调用
} catch (error) {
return Promise.reject(error);
}
})(0); //立即执行
});
server.listen(...args);
}
}
module.exports = Koa;

Comments NOTHING