非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
相关产品推荐
相关产品推荐

