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

非async函数返回Promise后调用结果为undefined的问题求助

问题:让非async函数返回Promise,但调用后结果为undefined

我想让一个非async的特定函数返回Promise,但调用该函数后得到的结果是undefined,以下是我的代码,请帮忙排查:

async function _callAccessControl(response, rpaReservation) {

  if (rpaResource.access_control_identifier && !accessControlExist) {
    return soap.createClientAsync('https://ipevia.com/public/files/onvif/credential.wsdl', {
      endpoint: 'https://ipevia.com/index.php?OnvifServer',
      forceSoap12Headers: true
    }).then((credentialClient) => {
      return credentialClient.CredentialService.CredentialPort.CreateCredential({
        Credential: {
          CredentialHolderReference: holderReference,
          CredentialIdentifier: {
            Type: {
              Name: 'pt:PIN',
              FormatType: 'SIMPLE_NUMBER16'
            },
            Value: rpaReservation.access_code
          },
          CredentialAccessProfile: {
            AccessProfileToken: rpaResource.access_control_identifier,
            ValidFrom: `${rpaReservationDateFormatted} ${rpaScheduleGrid.start_hour}:00`,
            ValidTo: `${rpaReservationDateFormatted} ${rpaScheduleGrid.end_hour}:00`
          }
        }
      }, function(err, result) {
        return rpaReservation.update({
          access_control_identifier: parseInt(result.Token, 10)
        }).then((updatedReservation) => {
          return updatedReservation;
        });
      }, { auth });
    });
  } else {
    return rpaReservation;
  }
}

_callAccessControl(response, rpaReservation).then((result) => {
  // result is undefined
})

问题排查与解决

核心原因

问题出在CreateCredential的调用逻辑上:你混用了回调函数和Promise链式调用,但传入回调函数时,CreateCredential不会返回Promise,导致你在.then((credentialClient) => { ... })里返回的是undefined,而非期望的rpaReservation.update()的Promise,最终整个函数的Promise解析结果为undefined。

另外注意:你当前的_callAccessControl已经是async函数,它本身就会自动返回Promise——不管你return普通值还是Promise,都会被包装成Promise返回。如果要改成非async函数,需要手动封装Promise逻辑。

修复方案

方案1:使用Promise化的API(优先推荐)

如果你的soap库提供了Promise版本的CreateCredential(比如命名为CreateCredentialAsync),直接用async/await简化逻辑:

async function _callAccessControl(response, rpaReservation) {
  if (rpaResource.access_control_identifier && !accessControlExist) {
    // 等待客户端创建完成
    const credentialClient = await soap.createClientAsync('https://ipevia.com/public/files/onvif/credential.wsdl', {
      endpoint: 'https://ipevia.com/index.php?OnvifServer',
      forceSoap12Headers: true
    });
    
    // 调用Promise版本的CreateCredential
    const result = await credentialClient.CredentialService.CredentialPort.CreateCredentialAsync({
      Credential: {
        CredentialHolderReference: holderReference,
        CredentialIdentifier: {
          Type: {
            Name: 'pt:PIN',
            FormatType: 'SIMPLE_NUMBER16'
          },
          Value: rpaReservation.access_code
        },
        CredentialAccessProfile: {
          AccessProfileToken: rpaResource.access_control_identifier,
          ValidFrom: `${rpaReservationDateFormatted} ${rpaScheduleGrid.start_hour}:00`,
          ValidTo: `${rpaReservationDateFormatted} ${rpaScheduleGrid.end_hour}:00`
        }
      }, { auth });
      
    // 等待更新完成并返回结果
    return await rpaReservation.update({
      access_control_identifier: parseInt(result.Token, 10)
    });
  } else {
    return rpaReservation;
  }
}

// 调用后即可获取正确结果
_callAccessControl(response, rpaReservation).then((result) => {
  // result为updatedReservation或原始rpaReservation
});

方案2:手动封装回调为Promise

如果库没有提供Promise化的API,就用Promise手动封装CreateCredential的回调逻辑:

async function _callAccessControl(response, rpaReservation) {
  if (rpaResource.access_control_identifier && !accessControlExist) {
    const credentialClient = await soap.createClientAsync('https://ipevia.com/public/files/onvif/credential.wsdl', {
      endpoint: 'https://ipevia.com/index.php?OnvifServer',
      forceSoap12Headers: true
    });
    
    // 手动将回调转为Promise
    const result = await new Promise((resolve, reject) => {
      credentialClient.CredentialService.CredentialPort.CreateCredential({
        Credential: {
          CredentialHolderReference: holderReference,
          CredentialIdentifier: {
            Type: {
              Name: 'pt:PIN',
              FormatType: 'SIMPLE_NUMBER16'
            },
            Value: rpaReservation.access_code
          },
          CredentialAccessProfile: {
            AccessProfileToken: rpaResource.access_control_identifier,
            ValidFrom: `${rpaReservationDateFormatted} ${rpaScheduleGrid.start_hour}:00`,
            ValidTo: `${rpaReservationDateFormatted} ${rpaScheduleGrid.end_hour}:00`
          }
        }
      }, (err, result) => {
        if (err) reject(err);
        else resolve(result);
      }, { auth });
    });
    
    return await rpaReservation.update({
      access_control_identifier: parseInt(result.Token, 10)
    });
  } else {
    return rpaReservation;
  }
}

方案3:改为非async函数(手动返回Promise)

如果要实现非async函数返回Promise的需求,需要手动在外层封装Promise:

function _callAccessControl(response, rpaReservation) {
  // 手动返回Promise
  return new Promise((resolve, reject) => {
    if (rpaResource.access_control_identifier && !accessControlExist) {
      soap.createClientAsync('https://ipevia.com/public/files/onvif/credential.wsdl', {
        endpoint: 'https://ipevia.com/index.php?OnvifServer',
        forceSoap12Headers: true
      })
      .then(credentialClient => {
        // 封装CreateCredential的回调为Promise
        return new Promise((innerResolve, innerReject) => {
          credentialClient.CredentialService.CredentialPort.CreateCredential({
            Credential: {
              CredentialHolderReference: holderReference,
              CredentialIdentifier: {
                Type: {
                  Name: 'pt:PIN',
                  FormatType: 'SIMPLE_NUMBER16'
                },
                Value: rpaReservation.access_code
              },
              CredentialAccessProfile: {
                AccessProfileToken: rpaResource.access_control_identifier,
                ValidFrom: `${rpaReservationDateFormatted} ${rpaScheduleGrid.start_hour}:00`,
                ValidTo: `${rpaReservationDateFormatted} ${rpaScheduleGrid.end_hour}:00`
              }
            }
          }, (err, result) => {
            if (err) innerReject(err);
            else innerResolve(result);
          }, { auth });
        });
      })
      .then(result => {
        return rpaReservation.update({
          access_control_identifier: parseInt(result.Token, 10)
        });
      })
      .then(updatedReservation => {
        resolve(updatedReservation);
      })
      .catch(err => {
        reject(err);
      });
    } else {
      resolve(rpaReservation);
    }
  });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 17:19:50