在实现 compose 前,我们先来了解一下什么洋葱模型。

洋葱模型

洋葱模型,它就是 Koa 中间件的一种串行机制,并且是支持异步的。Koa中间件机制就是函数式组合概念 Compose的概念,将一组需要顺序执行的函数复合为一个函数,外层函数的参数实际是内层函数的返回值。洋葱圈模型可以形象表示这种机制。

下面是官方的一张图,即著名的洋葱圈模型:
image.png

我们再来看一下中间件的执行顺序:
v2-b353e7e458d7542b366c1139b01b1a07_b.gif

下面是一个表达 “洋葱模型” 的经典案例:

  1. const Koa = require("koa");
  2. const app = new Koa();
  3. app.use(asycn (ctx, next) => {
  4. console.log(1);
  5. await next();
  6. console.log(2);
  7. });
  8. app.use(asycn (ctx, next) => {
  9. console.log(3);
  10. await next();
  11. console.log(4);
  12. });
  13. app.use(asycn (ctx, next) => {
  14. console.log(5);
  15. await next();
  16. console.log(6);
  17. });
  18. app.listen(3000);

根据中间件的执行顺序,上面代码输出的结果为:1 => 3 => 5 => 6 => 4 => 2

compose 实现

洋葱圈的核心实现是 compose 函数,我们来盘点一下 compose 的各种实现。

Koa 中 compose 的实现方式

koa 递归实现

  1. module.exports.compose = (middlewares = []) => {
  2. // 保证 middlewares 为数组
  3. if (!Array.isArray(middlewares)) {
  4. middlewares = Array.from(arguments);
  5. }
  6. // 保证 middlewares 的每一项为函数
  7. if (middlewares.some(fn => typeof fn !== 'function')) {
  8. throw new TypeError('Middleware must be composed of functions!');
  9. }
  10. return function () {
  11. // 取出第一个中间件函数执行
  12. return dispatch(0);
  13. // 递归函数
  14. function dispatch(i) {
  15. // 取出第 i 个中间件并执行
  16. let fn = middlewares[i];
  17. // 中间件函数不存在或者所有的中间件函数都执行完,返回成功态的 Promise
  18. if (!fn) {
  19. return Promise.resolve();
  20. }
  21. // 执行后返回成功态的 Promise
  22. return Promise.resolve(
  23. fn(function next() { // 执行下一个中间件函数
  24. return dispatch(i + 1);
  25. })
  26. );
  27. }
  28. };
  29. };

Koa Reduce 实现

  1. module.exports.compose = (middlewares = []) => () => {
  2. // 保证 middlewares 为数组
  3. if (!Array.isArray(middlewares)) {
  4. middlewares = Array.from(arguments);
  5. }
  6. // 保证 middlewares 内的每一项为函数
  7. if (middlewares.some(fn => typeof fn !== 'function')) {
  8. throw new TypeError('Middleware must be composed of functions!');
  9. }
  10. if (middlewares.length === 0) {
  11. // 没有中间件函数时返回 成功态的Promise
  12. return Promise.resolve();
  13. } else if (middlewares.length === 1) {
  14. // 只有一个中间件函数时,执行当前的中间件函数
  15. return Promise.resolve(middlewares[0].call(null, () => Promise.resolve()));
  16. } else {
  17. // compose reduce实现
  18. return middlewares
  19. .map(item => item)
  20. .reverse()
  21. .reduce((pre, cur) => () => cur(() => pre(() => {})))();
  22. }
  23. };

Koa Class 实现

  1. class ComposeClass {
  2. constructor() {
  3. this.middlewares = [];
  4. this.index = 0;
  5. }
  6. middleware(middlewares) {
  7. this.middlewares = middlewares;
  8. return this.dispatch(this.index);
  9. }
  10. dispatch(index) {
  11. const fn = this.middlewares[index];
  12. if (!fn) {
  13. return Promise.resolve();
  14. }
  15. this.index += 1;
  16. return Promise.resolve(fn(this.next.bind(this)));
  17. }
  18. // 指定下一个中间件的执行
  19. next() {
  20. return this.dispatch(this.index);
  21. }
  22. }
  23. module.exports.compose = (middlewares = []) => {
  24. if (!Array.isArray(middlewares)) {
  25. middlewares = Array.from(arguments);
  26. }
  27. if (middlewares.some(fn => typeof fn !== 'function')) {
  28. throw new TypeError('Middleware must be composed of functions!');
  29. }
  30. return () => {
  31. return new ComposeClass().middleware(middlewares);
  32. };
  33. };

express 中的 compose 实现

express 递归实现

  1. module.exports.compose = (middlewares = []) => {
  2. //
  3. if (!Array.isArray(middlewares)) {
  4. middlewares = Array.from(arguments);
  5. }
  6. if (middlewares.some(fn => typeof fn !== 'function')) {
  7. throw new TypeError('Middleware must be composed of functions!');
  8. }
  9. return async () => {
  10. let idx = 0;
  11. async function next() {
  12. if (idx === middlewares.length) {
  13. return Promise.resolve();
  14. }
  15. if (idx < middlewares.length) {
  16. return Promise.resolve(middlewares[idx++](next));
  17. }
  18. }
  19. return await next();
  20. };
  21. };

Redux 中的 compose 实现

Redux Reduce 实现

  1. module.exports.compose = (middlewares = []) => {
  2. if (!Array.isArray(middlewares)) {
  3. middlewares = Array.from(arguments);
  4. }
  5. if (middlewares.length === 0) {
  6. return arg => arg;
  7. }
  8. if (middlewares.some(fn => typeof fn !== 'function')) {
  9. throw new TypeError('Middleware must be composed of functions!');
  10. }
  11. return (next = async () => {}) => middlewares.reduce((a, b) => arg => a(() => b(arg)))(next);
  12. };

Redux ReduceRight 实现

  1. /**
  2. * @description: 利用reduceRight实现洋葱圈
  3. * @param {middlewares:中间件数组}
  4. * @return {高阶函数}
  5. */
  6. module.exports.compose = (middlewares = []) => {
  7. if (!Array.isArray(middlewares)) {
  8. middlewares = Array.from(arguments);
  9. }
  10. if (middlewares.some(fn => typeof fn !== 'function')) {
  11. throw new TypeError('Middleware must be composed of functions!');
  12. }
  13. // reduceRight:从右向左做累加,第二个参数为初始值
  14. // 比如:middlewares = [f1, f2, f3],执行过程如下:
  15. // 第一次 --> a = () => {}, b = f3,结果:() => f3(() => {})
  16. // 第二次 --> a = () => f3(() => {}), b = f2,结果:() => f2(() => f3(() => {}))
  17. // 第三次 --> a = () => f2(() => f3(() => {})),b = f1,结果:() => f1(() => f2(() => f3(() => {})))
  18. return () =>
  19. middlewares.reduceRight(
  20. (a, b) => () => b(a),
  21. () => {}
  22. )();
  23. };

Redux ReduxRight Promise 实现

  1. module.exports.compose = (middlewares = []) => {
  2. if (!Array.isArray(middlewares)) {
  3. middlewares = Array.from(arguments);
  4. }
  5. if (middlewares.some(fn => typeof fn !== 'function')) {
  6. throw new TypeError('Middleware must be composed of functions!');
  7. }
  8. return () =>
  9. Promise.resolve(
  10. middlewares.reduceRight(
  11. (a, b) => () => Promise.resolve(b(a)),
  12. () => Promise.resolve()
  13. )()
  14. );
  15. };

责任链模式实现

  1. class Handle {
  2. constructor(middleware) {
  3. this.middleware = middleware;
  4. this.next = null;
  5. }
  6. setNext(nextHandle) {
  7. this.next = nextHandle;
  8. }
  9. }
  10. module.exports.compose = (middlewares = []) => {
  11. if (!Array.isArray(middlewares)) {
  12. middlewares = Array.from(arguments);
  13. }
  14. if (middlewares.some(fn => typeof fn !== 'function')) {
  15. throw new TypeError('Middleware must be composed of functions!');
  16. }
  17. const handles = [];
  18. for (let i = 0; i < middlewares.length; i++) {
  19. const handle = new Handle(middlewares[i]);
  20. handles.push(handle);
  21. }
  22. for (let i = 0; i < handles.length; i++) {
  23. if (handles[i + 1]) {
  24. handles[i].setNext(handles[i + 1]);
  25. }
  26. }
  27. return function func() {
  28. return innerFunc(handles[0]);
  29. function innerFunc(currentHandle = handles[0]) {
  30. if (!currentHandle) {
  31. return Promise.resolve();
  32. }
  33. return Promise.resolve(currentHandle.middleware(() => innerFunc(currentHandle.next)));
  34. }
  35. };
  36. };

List 列表递归实现

  1. const isArray = action => Array.isArray(action)?true:false;
  2. const isFunction = middlewares => middlewares.every(middleware => typeof middleware === 'function');
  3. module.exports.compose = (args) => async () => {
  4. let middlewares = [...args]
  5. if(!isArray(middlewares)) throw new TypeError('middlewares must be Array');
  6. if(!isFunction(middlewares)){
  7. throw new TypeError('middleware must be Function')
  8. }
  9. if(middlewares.length === 0){
  10. return null;
  11. }
  12. //生成链表
  13. //{next:{fn:b,next:{fn:next}}}
  14. function getStatck(statck){
  15. if(middlewares.length>0){
  16. let fn = middlewares.shift()
  17. statck.next = { fn }
  18. getStatck(statck.next)
  19. return statck;
  20. }
  21. }
  22. let statck = getStatck({});
  23. let filber = statck.next;
  24. return dispatch(filber)
  25. function dispatch(filber){
  26. if(!filber){
  27. return () =>{}
  28. }
  29. return filber.fn(next = async()=>{
  30. await dispatch(filber.next)
  31. })
  32. }
  33. }

参考资料:https://github.com/su37josephxia/compose-awesome