AG-Grid异步valueGetter返回[object Promise]问题解决方案
问题原因
你的判断完全准确,问题根源是AG Grid的valueGetter本身不支持异步返回值:
- 所有标记了
async的函数,无论内部执行的逻辑是同步还是异步,返回值永远是一个Promise对象 - AG Grid调用
valueGetter拿到返回值后,不会等待Promise状态变更为fulfilled,会直接将返回值做字符串转换后渲染,因此所有单元格都会显示[object Promise] - 你在控制台能看到正确的打印结果,是因为Promise内部的await逻辑正常执行完成了,但这个结果是在AG Grid已经完成单元格渲染之后才拿到的,没法自动同步回单元格内容。
出现问题时的单元格显示效果:![单元格显示[object Promise]效果](https://i.sstatic.net/NpXkd.png)
可行实现方案
valueGetter的设计定位就是同步返回单元格值,JS本身也不存在不阻塞主线程的同步等待异步方法的方案,不要尝试在valueGetter内部包裹异步逻辑,可根据业务场景选择以下两种合规方案:
方案1:预加载依赖数据,保持valueGetter同步执行(性能最优,优先推荐)
不要在单元格取值阶段发API请求,在表格初始化、行数据加载阶段,就把所有格式化、计算需要的接口数据提前拉取完成,存入可同步访问的缓存或者合并进行数据对象中,valueGetter执行时直接读取预加载好的数据做计算即可。
示例代码:import { useState, useEffect } from 'react'; import { AgGridReact } from 'ag-grid-react'; function GridComponent() { const [gridReady, setGridReady] = useState(false); const [rowData, setRowData] = useState([]); const [calcDepData, setCalcDepData] = useState({}); useEffect(() => { const init = async () => { // 拉取原始表格行数据 const originRows = await fetch('/api/row-list').then(res => res.json()); // 提前拉取所有计算、格式化需要的依赖接口数据 const depData = await loadDataFunction(); setRowData(originRows); setCalcDepData(depData); setGridReady(true); }; init(); }, []); const defaultColDef = { valueGetter: (params) => { // 全程同步执行,直接读取预加载的依赖数据做计算 return doCalcFormat(params, calcDepData); } }; // 依赖数据未加载完成时显示加载态,不渲染表格 return gridReady ? ( <AgGridReact rowData={rowData} defaultColDef={defaultColDef} /> ) : <div>表格加载中...</div> }方案2:使用自定义cellRenderer处理异步逻辑(适配无法预加载的场景)
如果因为数据量过大、单元格依赖参数动态性太强无法提前预加载所有数据,就把异步逻辑从valueGetter移到自定义单元格渲染组件中,由组件自行管理异步请求、加载态和最终值渲染。
示例代码(React版本):import { useState, useEffect } from 'react'; // 异步单元格渲染组件 const AsyncFormatCell = (params) => { const [cellValue, setCellValue] = useState(''); const [loading, setLoading] = useState(true); useEffect(() => { let isMounted = true; setLoading(true); // 执行异步计算/接口请求 doCalcFormat(params).then(result => { if (isMounted) { setCellValue(result); setLoading(false); } }); // 组件卸载时取消更新,避免内存泄漏 return () => { isMounted = false }; }, [params.data, params.node.id]); // 监听行数据变化,重新触发计算 return loading ? <span className="cell-loading">加载中...</span> : <span>{cellValue}</span>; }; const defaultColDef = { // 移除异步的valueGetter,异步逻辑全部交给cellRenderer处理 cellRenderer: AsyncFormatCell };
注意:绝对不要通过死循环轮询Promise状态的方式在valueGetter里做同步等待,这种写法会直接阻塞JS主线程,导致整个页面卡死。
内容的提问来源于stack exchange,提问作者mmarion
相关产品推荐
相关产品推荐

