使用Promises或Async/Await填充表单遇值覆盖问题求助
问题根源分析
你的代码里有几个关键问题导致异步操作顺序混乱,进而出现值被覆盖的情况:
getJson没有返回 Promise:虽然getFSEs标了async,但内部用的是回调式的$.ajax,并没有把异步操作包装成Promise,所以async函数会立即返回一个已resolve的Promise,不会等待ajax请求完成。.then中错误地直接执行函数:比如.then(getPersons("itemResponsible", "Select Person...")),这里会立即执行getPersons,而不是等待前一个Promise完成后再执行,导致所有请求几乎同时发起,顺序完全不可控。getPunchlistItem可能在下拉填充完成前执行:如果getPunchlistItem先完成,后续下拉填充的操作会覆盖它设置的表单值。
修复步骤
第一步:改造 getJson 使其返回 Promise
jQuery的$.ajax本身就返回Promise,我们可以直接利用这一点,去掉回调参数,让getJson返回Promise:
function getJson(endpointUrl) { return $.ajax({ type: "GET", headers: { "accept": "application/json;odata=verbose", "content-type": "application/json;odata=verbose" }, url: endpointUrl }); }
第二步:重构异步函数(以getFSEs为例)
去掉回调,改用async/await处理异步请求,确保函数返回的Promise在ajax完成并填充下拉后才resolve:
async function getFSEs(el, allText, filter) { try { const data = await getJson(myURL + "PunchlistTracking/_api/web/lists/getbytitle('FSEs')/items"); myFSEs = data.d.results.map(FSE => [`${FSE.Id}`, `${FSE.Title}`, `${FSE.FSEName}`]); let output = `<option value='0' selected='selected'>${allText}</option>`; for (let i = 0; i < myFSEs.length; i++) { // 注意:原代码里用了myFSEs[i][3],但map出来的数组只有3个元素(索引0-2),这里修正为对应索引 if ((myFSEs[i][2] == filter) || !filter) { output += `<option value='${myFSEs[i][0]}'>${myFSEs[i][1]} ${myFSEs[i][2]}</option>`; } } $(`#${el}`).html(output); return myFSEs; } catch (error) { logError(error); throw error; // 抛出错误让后续Promise链处理 } }
用同样的方式重构getPersons和getTypes函数,确保它们都返回正确的Promise。
第三步:正确控制异步执行顺序
方式一:链式调用(顺序执行下拉填充)
注意要在.then里传函数引用,用箭头函数包裹避免立即执行:
var myFSEs = []; var myTypes = []; var myPeople = []; $(document).ready(function () { getFSEs("itemFSE", "Select FSE...") .then(() => getPersons("itemResponsible", "Select Person...")) .then(() => getTypes("itemType", "Select Type...")) .then(() => getPunchlistItem(myPLItemID)) .catch(error => console.error("请求出错:", error)); });
方式二:并行执行(效率更高)
如果三个下拉填充请求不需要顺序执行,可以用Promise.all并行发起,等所有请求完成后再调用getPunchlistItem:
$(document).ready(async function () { try { // 并行执行三个下拉填充请求 await Promise.all([ getFSEs("itemFSE", "Select FSE..."), getPersons("itemResponsible", "Select Person..."), getTypes("itemType", "Select Type...") ]); // 所有下拉填充完成后,再设置表单值 await getPunchlistItem(myPLItemID); } catch (error) { console.error("请求出错:", error); } });
第四步:确保getPunchlistItem也是异步函数
如果getPunchlistItem也是通过ajax获取数据并设置表单,同样要改造成返回Promise的函数:
async function getPunchlistItem(itemId) { try { const data = await getJson(myURL + `PunchlistTracking/_api/web/lists/getbytitle('PunchlistItems')/items(${itemId})`); // 设置表单值示例 $("#itemFSE").val(data.d.FSEId); $("#itemResponsible").val(data.d.ResponsibleId); $("#itemType").val(data.d.TypeId); return data.d; } catch (error) { logError(error); throw error; } }
修复原理
通过上述改造,我们确保了所有下拉框的填充操作都完成后,才执行getPunchlistItem设置表单值,这样后续就不会有异步操作覆盖已经设置好的值。同时,所有异步操作都通过Promise正确管理,执行顺序完全可控。
内容的提问来源于stack exchange,提问作者dikuw
相关产品推荐
相关产品推荐

