JavaScript Promise调用函数返回undefined 应在哪添加return语句?
问题根因
你遇到的返回undefined问题核心有两个:
- 异步操作没有正确返回Promise:
Xrm.WebApi.online.retrieveRecord本身是异步方法,返回Promise实例,但你没有把它作为checktheData的返回值,导致调用checktheData时不等异步请求完成就直接返回了undefined。 - 异步逻辑和同步逻辑顺序错误:依赖
checktheData返回结果的逻辑现在写在Promise回调之外,代码执行时异步请求还没完成,自然拿不到结果,而且你加的调试用return直接中断了后续代码执行。
具体修改位置
1. 修改checktheData函数,补充return语句
在Xrm.WebApi.online.retrieveRecord调用前加return,让整个函数返回异步请求的Promise,同时注意把原来字符串类型的"false"改成布尔值,避免后续判断出错,你回调里返回的outcomeString就能正常向外传递:
function checktheData(recordidGuid){ var outcomeString = "" var checkOutcome = false; // 原代码此处为字符串"false",已修正为布尔值 var str = ""; // 新增return,返回异步请求的Promise实例 return Xrm.WebApi.online.retrieveRecord("new_apprenticeshipflight", recordidGuid, "?$select=new_flighttype,new_programmelearningaimreference,new_apprenticeshipoverallaimreference,_new_mentor_value,_new_enrolledstandard_value,_new_clonelinkid_value,new_plannedstartdate,new_plannedenddate,crd80_overideendcalc,_new_contact_value,_new_apprenticeshipprogramme_value,_new_employer_value,_crd80_locationcontact_value,crd80_headofficedelivery,crd80_learningjournalurl,crd80_refineryid,crd80_addresstouse,_crd80_placementemployer_value,crd80_employeraddresstext,&$expand=new_Contact($select=emailaddress1,firstname,lastname),new_EnrolledStandard($select=crd80_learningjournalform),crd80_PlacementEmployer($select=name, accountid, address1_postalcode,address2_postalcode),crd80_LocationContact($select=emailaddress1,fullname,telephone1),new_Employer($select=name,address1_postalcode,address2_postalcode),new_Mentor($select=new_homepostcode),new_ApprenticeshipProgramme($select=crd80_learnerteamsiteurl)").then( function success(result) { if (result["new_flighttype"] == 100000001 && result["new_flighttype"] == null){ outcomeString = outcomeString + "This must be a learner type flight"; checkOutcome = true }; // 其他校验逻辑保留 console.log(outcomeString) // 把校验结果和描述一起返回,方便外层使用 return { checkOutcome: checkOutcome, outcomeString: outcomeString } }) }
2. 修改masterDeploy中的Promise调用逻辑
不需要手动new Promise包一层checktheData,直接调用即可,同时把所有依赖校验结果的逻辑都放到.then回调中,还要删掉调试用的中断return:
function masterDeploy(PrimaryControl){ var formContext = PrimaryControl; formContext.data.refresh(true); var recordidGuid = formContext.data.entity.getId(); var loggedinuser = Xrm.Utility.getGlobalContext().userSettings.userId; recordidGuid = recordidGuid.replace('{', '').replace('}', ''); loggedinuser = loggedinuser.replace('{', '').replace('}', ''); // 直接调用checktheData,它已经返回Promise实例 checktheData(recordidGuid) .then(result => { // 这里拿到的result就是checktheData返回的校验结果 const {checkOutcome, outcomeString} = result; const alertOptions = { height: 500, width: 1000 }; if (checkOutcome == true){ var alertStrings = { confirmButtonLabel: "Close", text: outcomeString, title: "Data check failed" }; return Xrm.Navigation.openAlertDialog(alertStrings, alertOptions); } // 校验通过,执行后续步骤 buildLearnerEntryURL(recordidGuid,loggedinuser) createUserandEnrol(recordidGuid,loggedinuser) createLearningAims(recordidGuid) formContext.data.refresh(true); // 弹出完成提示 var alertStrings = { confirmButtonLabel: "Close", text: "Deployment completed etc etc", title: "Deployment Completed" }; return Xrm.Navigation.openAlertDialog(alertStrings, alertOptions); }) .catch(function (error){ DisplayError(error) }); }
额外注意事项
- 不要把
checkOutcome和outcomeString分散在多个函数里定义为局部变量,通过Promise的返回值传递更安全,不会出现作用域混乱的问题。 - 如果
buildLearnerEntryURL、createUserandEnrol这些方法也是异步的,也要按Promise的链式调用规则处理,确保执行顺序正确。
内容的提问来源于stack exchange,提问作者Martin Hutchins
相关产品推荐
相关产品推荐

