核心概念
理解 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) => O5 种常见的砖块模式:
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 → 后置处理
- ✅ 类型安全:输入输出类型由泛型约束
