函数组合是构建洋葱圈模型跨端网络适配层的自然工具,通过纯函数逐层包裹请求与响应,形成由内而外的数据流闭环;各层职责分明:最内层处理业务语义,中间层注入通用策略,最外层对接平台原生能力,所有适配器接收统一请求结构并归一化错误。

函数组合是构建洋葱圈模型跨端网络适配层的自然工具——它让每一层职责清晰、输入输出确定、可插拔且无副作用。核心不在于“套用洋葱图”,而在于用纯函数逐层包裹请求与响应,形成由内而外的数据流闭环。
明确各层函数职责与数据契约
洋葱圈模型在此场景下不是物理分层,而是逻辑包裹链。每层函数接收上一层输出,加工后传给下一层,最终返回统一结构(如 { data, error, meta })。关键约束:
-
最内层(领域协议层):只处理业务语义,例如
normalizeOrderPayload(order),不关心 HTTP、序列化或重试; -
中间层(传输策略层):注入通用行为,如
withRetry(3)、withTimeout(8000)、withAuthHeader(token); -
最外层(端适配层):对接具体运行时,如
fetchAdapter(Web)、rnFetchAdapter(React Native)、uniRequestAdapter(UniApp),它们把标准化请求对象转为平台原生调用。
用高阶函数实现可组合的中间件链
每一层都应是接收函数、返回函数的高阶函数,支持自由拼接:
const compose = (...fns) => (input) => fns.reduceRight((acc, fn) => fn(acc), input);
// 示例中间件
const withLogging = next => async (req) => {
console.log('→', req.url);
const res = await next(req);
console.log('←', res.status);
return res;
};
const withJSONBody = next => async (req) => {
if (req.body && typeof req.body === 'object') {
return next({ ...req, body: JSON.stringify(req.body), headers: { ...req.headers, 'Content-Type': 'application/json' } });
}
return next(req);
};
// 组装成洋葱:从外向内定义执行顺序,但数据流由内而外
const requestPipeline = compose(
fetchAdapter,
withJSONBody,
withLogging,
normalizeOrderPayload
);
注意:compose 从右往左执行,所以 normalizeOrderPayload 最先被调用(最内),fetchAdapter 最后执行(最外),符合洋葱依赖方向。
跨端适配的关键在于“统一输入,隔离实现”
不同端对网络能力支持不一(如 Web 支持 AbortController,小程序不支持),因此外层适配器必须屏蔽差异:
- 所有适配器接收相同结构的
request对象(含url、method、body、timeout、signal等字段); - 适配器内部做平台判断:RN 调用
fetch+timeout-promise模拟 signal;小程序调用uni.request并将timeout映射为timeout字段; - 错误统一归一为
{ error: { type: 'NETWORK_ERROR', code: 'TIMEOUT' } },避免上层处理平台特有异常类型。
支持运行时动态切换与策略注入
洋葱圈不是静态结构,而是可编程管道。例如根据环境或用户身份切换 CDN 或灰度网关:
const getAdapter = (env) => {
if (env === 'cn') return cdnAdapter;
if (env === 'ab-test') return abGatewayAdapter;
return defaultAdapter;
};
const buildPipeline = (env, token) =>
compose(
getAdapter(env),
withAuthHeader(token),
withRetry(2),
normalizeOrderPayload
);
这种写法让“适配策略”成为一等公民,无需修改核心逻辑即可扩展接入方式,也便于单元测试(直接传入 mock adapter 即可验证整条链)。










