Skip to content

核心概念

理解 farrow-pipeline 的核心设计理念。

🧅 洋葱模型 - Pipeline 的灵魂

还记得你剥洋葱的经历吗?(希望没有流泪 😢)Pipeline 的执行模式就像洋葱一样,一层一层地嵌套:

外层 → 中层 → 内层 → 内层返回 → 中层返回 → 外层返回

用代码来说就是:

typescript
const pipeline = createPipeline<number, number>()

pipeline.use((input, next) => {
  console.log('🧅 外层:进入')
  const result = next(input)
  console.log('🧅 外层:退出')
  return result
})

pipeline.use((input, next) => {
  console.log('  🧅 中层:进入')
  const result = next(input)
  console.log('  🧅 中层:退出')
  return result
})

pipeline.use((input) => {
  console.log('    🧅 内层:到达核心')
  return input * 2
})

pipeline.run(5)

输出顺序

🧅 外层:进入
  🧅 中层:进入
    🧅 内层:到达核心
  🧅 中层:退出
🧅 外层:退出

💡 为什么这样设计? 洋葱模型让你可以在处理前处理后都执行代码。比如:请求前记录日志、请求后统计耗时。完美!

🧱 中间件 - Pipeline 的砖块

每个中间件就是一块砖,接收两个参数:

typescript
type Middleware<I, O> = (
  input: I,      // 当前输入
  next: Next<I, O>  // 调用下一个中间件
) => O

type Next<I, O> = (input?: I) => O

5 种常见的砖块模式

1. 🔄 转换型 - 改变输入

typescript
pipeline.use((input, next) => {
  const transformed = transform(input)
  return next(transformed)  // 传递新值给下一个
})

2. ✨ 增强型 - 处理结果

typescript
pipeline.use((input, next) => {
  const result = next(input)
  return addSomeSpice(result)  // 给结果加料
})

3. 🚧 拦截型 - 条件执行

typescript
pipeline.use((input, next) => {
  if (!isValid(input)) {
    return '滚!'  // 直接返回,不调用 next
  }
  return next(input)  // 放行
})

4. 🎁 包装型 - 前后处理

typescript
pipeline.use((input, next) => {
  console.log('之前')
  const result = next(input)
  console.log('之后')
  return result
})

5. 🛑 终止型 - 最后一站

typescript
pipeline.use((input) => {
  return '到此为止!'  // 不调用 next
})

执行流程详解

完整执行示例

typescript
const pipeline = createPipeline<number, string>()

// 中间件 1: 验证
pipeline.use((input, next) => {
  console.log('1️⃣ 验证输入:', input)
  if (input < 0) {
    return '错误:负数'  // 提前返回,不调用 next
  }
  return next(input)
})

// 中间件 2: 转换
pipeline.use((input, next) => {
  console.log('2️⃣ 转换:', input)
  const doubled = input * 2
  return next(doubled)
})

// 中间件 3: 格式化
pipeline.use((input, next) => {
  console.log('3️⃣ 格式化:', input)
  const result = next(`Number: ${input}`)
  console.log('3️⃣ 格式化完成')
  return result
})

// 中间件 4: 最终处理
pipeline.use((input) => {
  console.log('4️⃣ 最终处理:', input)
  return input.toUpperCase()
})

// 执行
pipeline.run(5)

输出

1️⃣ 验证输入: 5
2️⃣ 转换: 5
3️⃣ 格式化: 10
4️⃣ 最终处理: Number: 10
3️⃣ 格式化完成

中断执行

typescript
const pipeline = createPipeline<number, string>()

pipeline.use((input, next) => {
  if (input > 100) {
    return '太大了!'  // 直接返回,后续中间件不执行
  }
  return next(input)
})

pipeline.use((input) => {
  return `值: ${input}`  // 只有 input <= 100 才会执行
})

console.log(pipeline.run(50))   // "值: 50"
console.log(pipeline.run(200))  // "太大了!"

类型系统

类型安全的好处

typescript
// ✅ 正确:类型匹配
const pipeline = createPipeline<number, string>()
  .use((x: number, next) => next(x + 1))     // number → number
  .use((x: number) => `结果: ${x}`)          // number → string

// ❌ 错误:类型不匹配
const pipeline = createPipeline<number, string>()
  .use((x: number, next) => next('错误'))    // 类型错误!next 期望 number
  .use((x: number) => x * 2)                 // 类型错误!应返回 string

类型推导

typescript
const pipeline = createPipeline<number, string>()

pipeline.use((input, next) => {
  // input 自动推导为 number
  // next 的参数自动推导为 number
  // 返回值必须是 string 或 next 的返回值
  return next(input)
})

Next 函数的工作原理

调用 next() 时发生了什么

typescript
pipeline.use((input, next) => {
  console.log('调用 next 之前')
  const result = next(input)  // 执行后续所有中间件
  console.log('调用 next 之后')
  return result
})

修改传递给下一个中间件的值

typescript
pipeline.use((input, next) => {
  // 传递修改后的值
  return next(input * 2)
})

pipeline.use((input, next) => {
  // 传递不同类型(如果类型允许)
  return next(input.toString())
})

不调用 next 的后果

typescript
pipeline.use((input, next) => {
  // 如果不调用 next,后续中间件都不会执行
  if (shouldStop(input)) {
    return '停止'
  }
  return next(input)  // 只有在条件满足时才继续
})

实用模式

模式 1: 日志包装器

typescript
function withLogging<I, O>(
  middleware: Middleware<I, O>,
  name: string
): Middleware<I, O> {
  return (input, next) => {
    console.log(`[${name}] 输入:`, input)
    const result = middleware(input, next)
    console.log(`[${name}] 输出:`, result)
    return result
  }
}

// 使用
pipeline.use(
  withLogging((input, next) => next(input * 2), '加倍')
)

模式 2: 错误处理包装器

typescript
function withErrorHandling<I, O>(
  middleware: Middleware<I, O>,
  fallback: O
): Middleware<I, O> {
  return (input, next) => {
    try {
      return middleware(input, next)
    } catch (error) {
      console.error('中间件出错:', error)
      return fallback
    }
  }
}

// 使用
pipeline.use(
  withErrorHandling(
    (input, next) => {
      if (input < 0) throw new Error('负数')
      return next(input)
    },
    '出错了'
  )
)

模式 3: 条件中间件

typescript
function conditional<I, O>(
  condition: (input: I) => boolean,
  middleware: Middleware<I, O>
): Middleware<I, O> {
  return (input, next) => {
    if (condition(input)) {
      return middleware(input, next)
    }
    return next(input)
  }
}

// 使用
pipeline.use(
  conditional(
    (x) => x > 10,
    (x, next) => next(x * 2)
  )
)

核心原则总结

  • ✅ 中间件必须返回值
  • ✅ 调用 next(input) 继续到下一个中间件
  • ✅ 不调用 next() 会中断执行链
  • ✅ 洋葱模型:前置处理 → 调用 next → 后置处理
  • ✅ 类型安全:输入输出类型由泛型约束

这是一个第三方 Farrow 文档站 | 用 ❤️ 和 TypeScript 构建