1. Koa 中间件
Koa 的中间件通过一种更加传统的方式进行级联,摒弃了以往 node 频繁的回调函数造成的复杂代码逻辑。使用异步函数,我们可以实现"真正" 的中间件。与之不同,当执行到 yield next 语句时,Koa 暂停了该中间件,继续执行下一个符合请求的中间件(‘downstrem’),然后控制权再逐级返回给上层中间件(‘upstream’)。(koa中文文档的描述
)
在koa
的文档上有个非常代表性的中间件执行 gif
图。
2. Koa Compose 源码解析
2.1 test.js测试compose的代码,先对compose的使用有个了解
//test.js
function wait(ms) {return new Promise((resolve) => setTimeout(resolve, ms || 1));
}
function isPromise(x) {return x && typeof x.then === "function";
}
describe("Koa Compose", function () {it.only("should work", async () => {const arr = [];const stack = [];//这里删除了部分测试代码stack.push(async (context, next) => {arr.push(1);await wait(1);await next(); //dispatch(1)await wait(1);arr.push(6);});stack.push(async (context, next) => {arr.push(2);await wait(1);await next(); //dispatch(2)await wait(1);arr.push(5);});
//调用compose方法,传入异步任务队列,执行compose返回await compose(stack)({});expect(arr).toEqual(expect.arrayContaining([1, 2, 5, 6]));});
});
2.2. compose源码解析
function compose(middleware) {if (!Array.isArray(middleware))// 判断middleware是否是数组,判断数组的方法能想到几种呢throw new TypeError("Middleware stack must be an array!");for (const fn of middleware) {// 判断middleware里面的数据是否是函数, 顺便了解下for of 语法if (typeof fn !== "function")throw new TypeError("Middleware must be composed of functions!");}/** * @param {Object} context * @return {Promise} * @api public */return function (context, next) {// last called middleware #let index = -1;return dispatch(0);function dispatch(i) {if (i <= index)//如果i==index说明,同一个dispatch(fn里面的next)调用了多次,抛出错误return Promise.reject(new Error("next() called multiple times"));index = i;let fn = middleware[i];if (i === middleware.length) {// compose(stack)({}),没有传递第二个参数,所以next=undefinedfn = next;}if (!fn) {return Promise.resolve();}try {//这里取middleware的函数去执行,函数内部执行next(),执行middleware的下一个函数return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));} catch (err) {return Promise.reject(err);}}};
}
/*
测试脚本的调用流程
dispatch(0)
调用stack[0]的方法, 内部next()调用的是 dispach(1)arr=[1]dispach(1)
调用stack[1], next= dispatch(2)arr=[1,2]
当2==middleware.length ,compose(stack)({}),没有传递第二个参数,所以next=undefined
后面的就是顺序执行await wait(1);arr.push(5);await wait(1);arr.push(6);
*/
2.3. vsCode中debug方法截图
在package.json里找的script,有有Debug的按钮,点击选择执行test
扩展: redux中compose的代码
function compose(...funcs: Function[]) {if (funcs.length === 0) {// infer the argument type so it is usable in inference down the linereturn <T>(arg: T) => arg}if (funcs.length === 1) {return funcs[0]}return funcs.reduce((a, b) =>(...args: any) =>a(b(...args)))
}
3.小结
koa-compose
源码比较少,调试了好几遍才理解执行流程和原理。其中包含着闭包、Promise、bind等基础知识。 熟悉了 koa-compose
中间件常说的洋葱模型,学会了部分 jest 用法,如果单独执行某一个单元测试,可以使用it.only()。
it.only('should work', async () => {//xxxx
})
最后
整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。
有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享
部分文档展示:
文章篇幅有限,后面的内容就不一一展示了
有需要的小伙伴,可以点下方卡片免费领取