Skip to content

链式回调

链式回调是 OneBot Commander 的核心特性,它允许你将多个处理函数串联起来,形成处理流水线。

基本概念

什么是链式回调

链式回调允许你通过 action() 方法添加多个处理函数,这些函数会按顺序执行,前一个函数的返回值会作为下一个函数的输入。

typescript
const commander = new Commander('echo <message:text>');

commander
  .action((params) => {
    // 第一个处理函数
    return params.message.toUpperCase();
  })
  .action((upperMessage) => {
    // 第二个处理函数,接收第一个函数的返回值
    return upperMessage.length;
  })
  .action((length) => {
    // 第三个处理函数,接收第二个函数的返回值
    console.log(`消息长度: ${length}`);
    return length;
  });

回调函数参数

参数结构

每个回调函数接收以下参数:

typescript
function callback(params, ...remaining) {
  // params: 匹配到的参数对象
  // remaining: 剩余的消息段数组
}

参数示例

typescript
const commander = new Commander('test<arg1:text>[arg2:face]');

commander.action((params, ...remaining) => {
  console.log('参数对象:', params);
  // 输出: { arg1: 'hello', arg2: { type: 'face', data: { id: 1 } } }
  
  console.log('剩余消息段:', remaining);
  // 输出: [{ type: 'text', data: { text: 'extra' } }]
  
  return params.arg1;
});

返回值处理

返回值传递

每个回调函数的返回值会传递给下一个回调函数:

typescript
const commander = new Commander('process <text:text>');

commander
  .action((params) => {
    console.log('步骤1: 接收参数');
    return params.text;
  })
  .action((text) => {
    console.log('步骤2: 转换为大写');
    return text.toUpperCase();
  })
  .action((upperText) => {
    console.log('步骤3: 计算长度');
    return upperText.length;
  })
  .action((length) => {
    console.log('步骤4: 最终处理');
    return `处理完成,长度: ${length}`;
  });

返回值类型

回调函数可以返回任何类型的值:

typescript
commander
  .action((params) => {
    // 返回字符串
    return 'hello';
  })
  .action((str) => {
    // 返回数字
    return str.length;
  })
  .action((num) => {
    // 返回对象
    return { length: num, doubled: num * 2 };
  })
  .action((obj) => {
    // 返回数组
    return [obj.length, obj.doubled];
  });

异步链式回调

异步函数支持

回调函数可以是异步函数,支持 async/await

typescript
const commander = new Commander('async <id:number>');

commander
  .action(async (params) => {
    console.log('步骤1: 异步获取数据');
    const data = await fetchData(params.id);
    return data;
  })
  .action(async (data) => {
    console.log('步骤2: 异步处理数据');
    const processed = await processData(data);
    return processed;
  })
  .action(async (processed) => {
    console.log('步骤3: 异步保存结果');
    const result = await saveResult(processed);
    return result;
  });

混合同步和异步

可以在同一个链中混合使用同步和异步函数:

typescript
commander
  .action((params) => {
    // 同步处理
    console.log('同步步骤1');
    return params.id;
  })
  .action(async (id) => {
    // 异步处理
    console.log('异步步骤2');
    const data = await fetchData(id);
    return data;
  })
  .action((data) => {
    // 同步处理
    console.log('同步步骤3');
    return data.name;
  })
  .action(async (name) => {
    // 异步处理
    console.log('异步步骤4');
    const result = await saveName(name);
    return result;
  });

错误处理

异常传播

链式回调中的异常会向上传播:

typescript
const commander = new Commander('error <text:text>');

commander
  .action((params) => {
    console.log('步骤1: 正常执行');
    return params.text;
  })
  .action((text) => {
    console.log('步骤2: 抛出异常');
    throw new Error('处理失败');
  })
  .action((result) => {
    // 这个函数不会执行,因为前一个函数抛出了异常
    console.log('步骤3: 不会执行');
    return result;
  });

// 调用时需要捕获异常
try {
  const result = commander.match(segments);
} catch (error) {
  console.error('链式回调异常:', error.message);
}

错误恢复

可以在回调函数中处理异常:

typescript
commander
  .action((params) => {
    try {
      return processData(params.text);
    } catch (error) {
      console.error('处理失败,使用默认值');
      return 'default';
    }
  })
  .action((data) => {
    // 即使前一个函数出错,这个函数仍会执行
    return data.toUpperCase();
  });

高级用法

条件处理

根据参数或中间结果进行条件处理:

typescript
const commander = new Commander('conditional <type:text> <value:text>');

commander
  .action((params) => {
    return { type: params.type, value: params.value };
  })
  .action((data) => {
    // 根据类型进行不同处理
    switch (data.type) {
      case 'text':
        return data.value.toUpperCase();
      case 'number':
        return Number(data.value) * 2;
      case 'json':
        return JSON.parse(data.value);
      default:
        throw new Error(`不支持的类型: ${data.type}`);
    }
  })
  .action((processed) => {
    return { result: processed, timestamp: Date.now() };
  });

数据转换流水线

创建数据转换流水线:

typescript
const commander = new Commander('pipeline <data:text>');

commander
  .action((params) => {
    // 步骤1: 解析数据
    return JSON.parse(params.data);
  })
  .action((parsed) => {
    // 步骤2: 验证数据
    if (!parsed.name || !parsed.age) {
      throw new Error('数据格式不正确');
    }
    return parsed;
  })
  .action((validated) => {
    // 步骤3: 转换数据
    return {
      name: validated.name.toUpperCase(),
      age: validated.age,
      category: validated.age < 18 ? 'minor' : 'adult'
    };
  })
  .action((transformed) => {
    // 步骤4: 格式化输出
    return `${transformed.name} (${transformed.age}) - ${transformed.category}`;
  });

分支处理

根据条件创建不同的处理分支:

typescript
function createCommander(type) {
  const commander = new Commander(`${type} <data:text>`);
  
  if (type === 'user') {
    commander
      .action((params) => ({ type: 'user', data: params.data }))
      .action((data) => processUserData(data))
      .action((processed) => saveUser(processed));
  } else if (type === 'product') {
    commander
      .action((params) => ({ type: 'product', data: params.data }))
      .action((data) => processProductData(data))
      .action((processed) => saveProduct(processed));
  }
  
  return commander;
}

const userCommander = createCommander('user');
const productCommander = createCommander('product');

性能优化

1. 避免不必要的计算

typescript
commander
  .action((params) => {
    // 只在需要时进行昂贵计算
    if (params.needExpensive) {
      return expensiveCalculation(params.data);
    }
    return params.data;
  })
  .action((data) => {
    // 后续处理
    return processData(data);
  });

2. 缓存中间结果

typescript
const cache = new Map();

commander
  .action((params) => {
    const key = params.id;
    if (cache.has(key)) {
      return cache.get(key);
    }
    const result = expensiveCalculation(params.data);
    cache.set(key, result);
    return result;
  })
  .action((cached) => {
    return processCachedData(cached);
  });

3. 并行处理

typescript
commander
  .action(async (params) => {
    // 并行执行多个异步操作
    const [result1, result2, result3] = await Promise.all([
      asyncOperation1(params.data),
      asyncOperation2(params.data),
      asyncOperation3(params.data)
    ]);
    
    return { result1, result2, result3 };
  })
  .action((results) => {
    return combineResults(results);
  });

调试技巧

1. 添加日志

typescript
commander
  .action((params) => {
    console.log('步骤1 输入:', params);
    const result = processStep1(params);
    console.log('步骤1 输出:', result);
    return result;
  })
  .action((input) => {
    console.log('步骤2 输入:', input);
    const result = processStep2(input);
    console.log('步骤2 输出:', result);
    return result;
  });

2. 性能监控

typescript
function withTiming(fn, name) {
  return async (...args) => {
    const start = performance.now();
    const result = await fn(...args);
    const end = performance.now();
    console.log(`${name} 耗时: ${end - start}ms`);
    return result;
  };
}

commander
  .action(withTiming(async (params) => {
    return await expensiveOperation(params);
  }, '步骤1'))
  .action(withTiming(async (data) => {
    return await anotherExpensiveOperation(data);
  }, '步骤2'));

3. 错误追踪

typescript
function withErrorHandling(fn, stepName) {
  return async (...args) => {
    try {
      return await fn(...args);
    } catch (error) {
      console.error(`步骤 ${stepName} 出错:`, error);
      throw error;
    }
  };
}

commander
  .action(withErrorHandling(async (params) => {
    return await riskyOperation(params);
  }, '风险操作'))
  .action(withErrorHandling(async (data) => {
    return await anotherRiskyOperation(data);
  }, '另一个风险操作'));

最佳实践

1. 单一职责

每个回调函数应该只负责一个特定的任务:

typescript
// ✅ 好的设计
commander
  .action((params) => validateInput(params))
  .action((validated) => processData(validated))
  .action((processed) => formatOutput(processed));

// ❌ 不好的设计
commander.action((params) => {
  // 一个函数做太多事情
  const validated = validateInput(params);
  const processed = processData(validated);
  return formatOutput(processed);
});

2. 错误处理

在每个可能出错的地方添加适当的错误处理:

typescript
commander
  .action((params) => {
    try {
      return validateAndParse(params);
    } catch (error) {
      console.error('验证失败:', error);
      return { error: error.message };
    }
  })
  .action((data) => {
    if (data.error) {
      return { success: false, error: data.error };
    }
    return processData(data);
  });

3. 类型安全

使用 TypeScript 确保类型安全:

typescript
interface Step1Result {
  id: number;
  name: string;
}

interface Step2Result {
  processed: boolean;
  data: Step1Result;
}

const commander = new Commander('typed <id:number> <name:text>');

commander
  .action((params): Step1Result => {
    return { id: params.id, name: params.name };
  })
  .action((data: Step1Result): Step2Result => {
    return { processed: true, data };
  });

下一步


💡 提示

链式回调是 OneBot Commander 的强大特性,合理使用可以创建清晰、可维护的处理流水线。

Released under the MIT License.