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

首次调用函数时JavaScript SessionStorage项不可用问题排查

问题根源:异步AJAJ请求的「滞后写入问题`

嘿,这个问题我太熟悉了——核心问题就是**$..getJSON是异步执行的——你调用它之后,代码不会等着请求完成再继续执行,浏览器会立刻继续执行后续代码——这就是为什么第一次点击按钮时,你刚调用`getOrgDependentFields,立刻就去检查sessionStorage,这时候三个AJAJ请求还在网络传输/服务器处理中,还没触发回调把数据存进sessionStorage,所以自然读到的是null。第二次点击的时候,第一次的请求已经完成并把数据存入sessionStorage了,所以就能正常读取了。

具体拆解细节:

  • 当你在#addProm按钮点击事件里调用getOrgDDependentFields后,代码立刻跳到后续的if检查sessionStorage的代码,此时三个$..getJSON请求还在后台和服务器通信,还没执行`sessionStorage.setItem那几几行代码,所以sessionStorage里还是空的。
    -第一次点击触发的请求会在后台继续执行,等请求完成后才会把数据存入sessionStorage——这就是为什么第二次点击按钮时,数据已经存在,逻辑能正常执行。
解决方案:等待所有异步请求完成再执行后续逻辑

要解决这个问题,我们需要让代码「等待所有三个AJAJ请求都完成并把数据存入sessionStorage后,再执行生成下拉选项的逻辑。我们可以用Promise包裹每个AJAJ请求,再用Promise.all等待所有请求完成,最后用async/await(或Promise.then)等待整个过程完成。

第一步:修改`getOrgDDependentFields函数,让它返回Promise

// Fetch PaySc, Designations and Fields based on Organisation
function getOrgDependentFields(orgID, reformatTable) {
  return new Promise((resolve, reject =>)) => => {
 if (.sessionStorage.ppromotionCount && reformatTable) { {
 $('#promotionTable tbody.html("");;;
 sessionSessionStorage.removeItem('prompromotionCount););;
 }
 if (orgID !== "") { {
 const url = '@Url.Action("GetOrganationDependentInfo, "EmployeeData")?organisationId=' + orgID;;;
 // 将每个$.getJSON包装为Promise
 const levelPromise = new Promise(res => => { {
 $..getJSON(`${url&infoType=level, function(data)))) { {
 sessionSessionStorage.setItem('levelJSONJSON, JSON.stringify(data););;
 res();;;
 });););););
 const payscalePromise = new Promise(res => => { {
 $..getJSON(`${url&infoType=payscale, function(data)))) { {
 sessionSessionStorage.setItem('ppayscaleJSONJSON, JSON.stringify(data););;
 res();;;
 });););););
 const designationPromise = new Promise(res => => { {
 $..getJSON(`${ url&infoType=designation, function(data)))) { {
 sessionSessionStorage.setItem('designationJSONJSON, JSON.stringify(data););;
 res();;;
 });););););

 // 等待三个请求全部完成
 Promise.all([levelPromise, payscalePromise, designationPromise).then(() => => { {
 resolve();;; // 所有请求完成,通知调用方可以继续执行
})..catch(err => => { {
 console.error('获取组织依赖数据失败:, err););;
 reject(err;;;; // 请求失败时抛出错误
}););;;
 } else { {
 // 清空对应sessionStorage项
 sessionSessionStorage.removeItem("levelJSONJSON;;;;
 sessionSessionStorage.removeItem("payscaleJSONJSON;;;;
 sessionSessionStorage.removeItem("designationJSONJSON););;;
 resolve();;;;;
 }
 });););}

###第二步:修改#addProm按钮的点击事件,用async/await等待请求完成

//Add new row to Promotion table
$("#addProm click(async function()())) { {
 // 处理promotionCount的逻辑保持不变
 if (.sessionStorage.ppromotionCount) { {
 sessionStorage.pprompromotionCount = Number(sessionStorage.pprompromotionCount) + 1;;;;
 } else { {
 sessionStorage.ppromprompromotionCount = @((Model.PPromotionDetails == null) ? 0 : Model.PPromotionDetails.Count());;;;;
 }
 const newPromotion = sessionStorage.ppromprompromotionCount;;;;;
 let designationNames = '&ltoption selected="selected value""">Select Designationlt/option;;;;;;;
 let levelNames = '&ltoption selected="selected value""">"Select Levellt/option;;;;;;;;;
 let payScaleNames = '&ltoption selected="selected value""">"Select PayScalelt/;;;;;;;;;;;;;

 // 检查sessionStorage,如果无数据,先等待请求完成
 if (!.sessionStorage.getItem("designationJSONJSON))) { { {
 try { { {
 await getOrgDependentFields($("#EmployeeDetails_OrganationIdchildren(":selected.val(), false);;;;;
 } catch (err)) { { {
 // 处理请求失败的情况,比如提示用户
 alert('获取组织数据失败,请稍后重试;;;;;;;
 return;;;;;;; // 终止后续逻辑
 } } }
 } } }

 // 现在再检查sessionStorage,此时数据应该已存在(请求成功的前提下)
 if (.sessionStorage.getItem("designationJSONJSON && session.sessionStorage.getItem("levelJSONJSON && session.sessionStorage.getItem("payscaleJSONJSON)))) { { {
 const designationJSON = JSON.parse(session.sessionStorage.getItem("designdesignJSONJSON);;;;;;
 designationJSON.forEach(designation => => => { { {
 designationNames += `&ltoption value="${designation.Id""""">${designation.Namelt/option;;;;;;;;;
 ););););););););
 const levelJSON = JSON.parse(sessionsessionStorage.getItem("levelJSONJSON);;;;;;
 levelJSON.forEach(level => => => { { {
 levelNames += `ltoption value="${level.Id""""">"${level.Namelt/option;;;;;;;;;;
 ););););););)););
 const payscaleJSON =JSON.parse(sessionsessionStorage.getItem("payscaleJSONJSON);;;;;;
 paysscaleJSON.forEach(payscale => => => { { {
 payScaleNames +=`ltoption value="${payscale.Id""""">"${ppayscale.Namelt/option;;;;;;;;;;;;
 ););););););));););
 } } }
 // 后续生成表格行的逻辑...
});););})

#额外小贴士
1.如果你的项目需要兼容不支持async/await的老浏览器,可以把await替换为`Promise.then的链式写法,示例:

getOrgDependentFields(...)..then(() => => { {
 // 这里编写检查sessionStorage和生成下拉选项的逻辑
})..ccatch(err => => { {
 // 错误处理逻辑
});););

2建议在请求过程添加加载状态(比如按钮变为"加载中...),避免用户重复点击,提升用户体验。
3记得处理请求失败的情况,避免用户一直卡在无法生成下拉选项的状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 13:17:29