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

使用async parallel启动时报UNHANDLEDREJECTION回调已被调用错误如何解决

错误根因

你遇到的Callback was already called.错误本质是async.parallel的同一个任务回调被多次调用,或者部分任务的回调未按约定格式调用,核心问题有3个:

  • 不同任务的错误回调格式不统一:task1错误时用callback(err, null)符合async约定,但task2、task3、task5错误时用了callback(null, err),把错误对象当成成功返回值传递,导致async无法正确识别任务失败,逻辑混乱。
  • 数据库查询回调缺少兜底分支:所有查询回调仅处理了err和查询结果存在两种场景,如果查询成功但返回空值(比如Mongo未查到匹配数据返回null),会导致任务回调永远不会被触发,或者后续逻辑异常触发重复调用。
  • 回调式方法与async/await混用不兼容:loadMongoData是回调风格的方法,不返回Promise,你在init中用await调用不会等待加载完成,可能导致逻辑时序错误。
修复方案

1. 统一所有任务的回调格式,补充兜底分支

修正所有任务的回调逻辑,确保每个任务的回调有且仅被调用一次,示例(以task1、task2为例,其余task3、task5同理修改):

// 修正后的task1
task1: function (callback) {
  CriteriaDef.find({})
    .lean()
    .exec(function (err, criteriaDefs) {
      if (err) {
        console.log('Inside err 1')
        logger.error('Error fetching CriteriaDef: ', util.inspect(err));
        // 错误直接返回,第一个参数传err
        return callback(err);
      } 
      // 兜底分支,不管结果是否存在都执行
      console.log('Inside criteriaDefs')
      if (criteriaDefs?.length > 0) {
        console.log('Inside criteriaDefs 1')
        global.CRITERIA_DEFS = criteriaDefs;
        cache['criteria_defs'] = criteriaDefs;
      }
      callback(null, null);
    });
},
// 修正后的task2
task2: function (callback) {
  groupDef
    .find({})
    .lean()
    .exec(function (err, groupDefs) {
      if (err) {
        console.log('Inside err2')
        logger.error('Error fetching groupDefs: ', util.inspect(err));
        // 错误直接返回,第一个参数传err
        return callback(err);
      } 
      console.log('Inside ')
      global.groupDefsWithRoles = groupDefs || [];
      let _groupDefs = [];
      _.each(groupDefs || [], function (groupDef) {
        var data = {
          value: groupDef._id,
          label: `${groupDef._id}: ${groupDef.description}`
        };
        _groupDefs.push(data);
      });
      global.groupDefs = _groupDefs;
      cache['groupDefs'] = _groupDefs;
      logger.info('Loaded groupDefs: ', global.groupDefs.length);
      callback(null, null);
    });
},

2. 适配async/await调用,将loadMongoData改为返回Promise

修改loadMongoData方法,用Promise包装异步逻辑,适配init中的await调用:

loadMongoData(env) {
  const _this = this;
  console.log('Inside loadMongoData')
  // 返回Promise适配async/await
  return new Promise((resolve, reject) => {
    async.parallel(
      {
        // 上面修正后的6个任务逻辑
      },
      function (err, results) {
        if (err) {
          console.log('Inside final error')
          logger.error("Something went wrong can't start the app: ", util.inspect(err));
          return reject(err);
        } 
        console.log('Inside final else')
        logger.info('loaded all globals properly :)');
        resolve();
      }
    )
  })
}

3. 校验第三方方法回调逻辑

检查sisp.loadProducts方法的实现,确保它传入的回调只会被调用一次,不会内部触发多次回调导致错误。


内容的提问来源于stack exchange,提问作者Pravin Kottawar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 21:09:03