You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用函数解构调用index模块触发TypeError: callback未定义

问题排查与解决方案

看起来你遇到的TypeError: callback is not a function错误,根源在于测试时缺少必要参数导致函数调用的参数顺序错乱,加上async.waterfall的使用存在一些小疏漏,具体分析和解决步骤如下:

1. 核心原因:参数缺失导致回调位置被undefined占据

你的导出函数接收解构后的对象参数(redshiftDetails、sqs、lambda、redshiftQueryParams),但测试时只传入了redshiftDetails,其他参数(比如lambda)默认是undefined。

假设在getRedshiftCredentials函数内部,你调用getTemporaryRedshiftCredentials的代码类似这样:

helpers.getTemporaryRedshiftCredentials(redshiftDetails, lambda, callback);

由于测试时lambda是undefined,如果getTemporaryRedshiftCredentials的定义只需要两个参数(redshiftDetails和回调函数),那么第二个参数就变成了undefined(本该是回调的位置被undefined占据)。当Sinon的stub尝试调用这个“回调”时,自然会抛出callback is not a function错误。

2. 解决方案步骤

步骤1:给解构参数设置默认值,避免undefined

修改导出函数的参数定义,给可选参数设置空对象默认值,确保即使测试时只传部分参数,也不会出现undefined打乱参数顺序:

module.exports = function ({ 
  redshiftDetails, 
  sqs = {}, 
  lambda = {}, 
  redshiftQueryParams = {} 
}, callback) {
  // 原有逻辑...
}

步骤2:区分回调变量名,避免参数混淆

把async.waterfall步骤里的回调和外层的回调用不同变量名区分,防止变量名冲突导致的意外问题,同时确保调用工具函数时回调始终是最后一个参数:

function getRedshiftCredentials (sqsMessagesList, waterfallCallback) {
  logger.info('Obtaining redshift credentials...');
  // 明确传递正确的回调参数,避免被缺失的参数挤占位置
  helpers.getTemporaryRedshiftCredentials(redshiftDetails, (err, credentials) => {
    if (err) {
      return waterfallCallback(err); // 把错误传递给waterfall的下一步
    }
    // 后续业务逻辑...
    waterfallCallback(null, credentials);
  });
}

步骤3:给async.waterfall添加最终回调

你的代码里async.waterfall只定义了步骤数组,没有传递最终的回调函数,这会导致整个流程结束后无法触发外层的callback,测试里的done()可能永远不会被调用。补充最终回调:

async.waterfall([
  async.apply(helpers.bulkReceiveFromSQS, sqs),
  function getRedshiftCredentials (sqsMessagesList, waterfallCallback) {
    // 原有逻辑...
  },
  // 其他业务步骤...
], function (finalErr, finalResult) {
  // 把最终结果或错误传递给外层的callback
  if (finalErr) {
    logger.error('Ingestion workflow failed', finalErr);
    return callback(finalErr);
  }
  callback(null, metrics); // 传递最终结果
});

步骤4:测试时补充必要模拟参数(可选)

如果某些参数是工具函数必须的(比如sqs在bulkReceiveFromSQS里是必填项),测试时可以传入空的模拟对象,避免参数缺失引发其他问题:

it('should fail if the fetching temporary credentials of redshift fails', function (done) {
  stubbedGetTemporaryRedshiftCredentials.yields(new Error('call to getTemporaryRedshiftCredentials failed'));
  stubbedBulkReceiveFromSQS.yields(null);
  // 传入模拟的sqs和lambda对象
  ingestionController({ 
    redshiftDetails: {clusterId: 'someid', iamRole: 'somerole'},
    sqs: {},
    lambda: {}
  }, function (err) {
    expect(err).to.be.an('error');
    expect(err.message).to.be.equal('call to getTemporaryRedshiftCredentials failed');
    expect(stubbedRedshiftClose.callCount).to.be.equal(0);
    done();
  });
});

3. 验证修复

完成上述修改后,重新运行测试,TypeError应该会消失,测试逻辑也能正常触发外层的callback,调用done()结束测试。

内容的提问来源于stack exchange,提问作者Sayed Awesh Rahman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 10:22:42