TypeScript多条目场景执行sublistChanged触发RangeError栈溢出问题求助
问题根因
你遇到的栈溢出错误确实是递归触发sublistChanged事件导致的,具体触发逻辑如下:
- NetSuite客户端脚本的
sublistChanged事件会在子列表内容变更后触发,你在事件回调中对当前记录的体字段custbody_totalitemweightorder赋值、或者读取动态模式记录的子列表字段操作,都会间接重新触发sublistChanged事件,形成递归调用。 - 单条条目时递归深度低于JS引擎默认的调用栈上限(通常为10000层)不会报错,多条目时遍历子列表的过程中递归深度快速累加,就会触发栈溢出错误。
修复方案
下面给出几种可直接落地的修复方式:
方案1:加递归拦截标记(最便捷,改造成本最低)
在模块级别新增全局标记位,拦截自身逻辑触发的事件回调,避免递归执行:
// 模块级标记,标识当前是否正在执行重量计算逻辑 let isCalculatingWeight = false; export function sublistChanged (ctx: EntryPoints.Client.sublistChangedContext) { // 是自身逻辑触发的事件直接跳过,避免递归 if (isCalculatingWeight) return; try { isCalculatingWeight = true; const rec = X.getTx(ctx); const total = _.sumBy(rec.item, (line: POItemSublist | TOItemSublist) => line.quantity * line.custcol_atlas_item_weight!); rec.custbody_totalitemweightorder = total; } finally { // 计算结束后重置标记,保证后续用户操作能正常触发事件 isCalculatingWeight = false; } }
方案2:使用原生子列表API读取数据(性能更稳定,避免封装逻辑带来的额外触发)
不使用封装的X.getTx返回的动态模式记录对象,直接通过上下文提供的原生API读取子列表数据,减少不必要的事件触发:
export function sublistChanged (ctx: EntryPoints.Client.sublistChangedContext) { // 如果还是触发递归,可配合方案1的标记位使用 const currentRec = ctx.currentRecord; const itemLineCount = currentRec.getLineCount({ sublistId: 'item' }); let totalWeight = 0; for (let i = 0; i < itemLineCount; i++) { const quantity = currentRec.getSublistValue({ sublistId: 'item', fieldId: 'quantity', line: i }) as number; const weight = currentRec.getSublistValue({ sublistId: 'item', fieldId: 'custcol_atlas_item_weight', line: i }) as number; totalWeight += quantity * (weight || 0); } currentRec.setValue({ fieldId: 'custbody_totalitemweightorder', value: totalWeight }); }
方案3:调整触发时机(适合有二次优化需求的场景)
将重量计算逻辑迁移到fieldChanged事件中,仅在子列表的quantity或custcol_atlas_item_weight字段变更时触发计算,避免sublistChanged的频繁无效触发。
内容的提问来源于stack exchange,提问作者Alex O'Neill
相关产品推荐
相关产品推荐

