「我正在参与会员专属活动-源码共读第一期,点击参与」

本篇文章介绍的是compose函数。

可能听起来有点懵圈?下面会一一道来:

在咱们一般处理某个事务逻辑时,比如新增、删除、修改记载,在逻辑处理之前首先要校验一下用户的身份,处理完逻辑可能还得记载一下日志或许完结逻辑的耗时等等。这好办,咱们直接将这些校验和日志添加到事务逻辑里就好了,这样肯定是不行了,代码冗余。有没有更好的办法呢?

这样就要提到中间件middleware了。中间件的作用就是在恳求前和恳求后刺进逻辑,代码得到复用。

那如何将中间件和恳求组合起来履行呢?compose这时候就登场了。这儿以koa-compose为例。

koa-compose

安装

$ npm install koa-compose

使用

import compose from "koa-compose"
fn = compose([a, b, c, ...])

传入异步函数数组

源码

function compose (middleware) {
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
  for (const fn of middleware) {
    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) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve()
      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)))
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
  1. 首先是参数校验,传入的有必要是数组,其次每个数组的元素类型有必要是函数
  2. 回来值是一个函数, 传入了两个参数,分别是contextnext下一个履行的函数
  3. 回来的函数里声明了一个dispatch函数,首先校验了next多次调用
  4. 然后就是根据索引取到对应的中间件,经过Promise.resolve()履行该中间件,next传入下一个dispatch。并回来resolve,如果报错则回来Promise.reject(err),如果中间件执最终一个履行结束,则回来Promise.resolve()一个空的Promise目标。

相关的规划模式(责任链模式)

为了避免恳求发送者与多个恳求处理者耦合在一起,将一切恳求的处理者经过前一目标记住其下一个目标的引用而连成一条链;当有恳求发生时,可将恳求沿着这条链传递,直到没有目标处理它为止。

结束语

它的中心逻辑在dispatch函数里。每次等待上一个中间件履行结束之后,就履行一个,链式调用,确保了异步函数按次序履行。