如何解决d3.js v6折叠树通过选择器程序化访问数据的异常问题
更新
[2021-05-27:8天后] 我已自行解决该问题,可查看已采纳的答案。为简洁起见,我已编辑下方的原始问题,删除了与问题/解决方案不再相关的部分。
存在问题的原始代码为嵌入业务d3.js逻辑的HTML文件,该版本中我使用了以下自定义函数实现JSON数据加载、节点搜索与检索:
function myOntology(node) { d3.json("ontology.json").then(function(treeData) {...}}function findNode(node) { myOntology(node); }function getNode(node) {...}
最终解决方案简化了实现流程,不再依赖上述自定义函数。
原始问题(转述)
我在通过promise加载数据到d3.js v6折叠树后,遇到了程序化访问数据的相关问题:将JSON数据加载到d3可视化组件后,首次访问正常,但后续无法再次访问对应数据。
也就是说我似乎被“卡住”在初始数据加载阶段,我初步判断该问题是由promise/回调未正常退出导致,也可能存在其他未排查到的编码问题。
解决方案
问题根因
该问题的核心是数据重复加载+异步作用域隔离:
- 原代码的
myOntology函数每次被调用都会重新发起d3.json请求加载ontology.json,promise异步回调内部的treeData只在回调作用域内有效,外部无法长期访问 - 没有对已经加载完成的层级树数据做全局缓存,每次节点检索都要等新一轮数据加载完成,自然会出现首次访问正常、后续访问卡住的问题
可行修复方案
最终简化流程的优化核心通常包含以下2步:
- 数据预加载+全局缓存:只在页面初始化时请求一次JSON数据,加载完成后把加工好的d3层级树数据存在全局可访问的变量里,不需要每次查询都重新加载
// 全局缓存加载完成的树数据 let cachedTreeData = null; // 初始化时只加载一次 d3.json("ontology.json").then(treeData => { // 把原始JSON加工为d3折叠树可用的层级结构 cachedTreeData = d3.hierarchy(treeData); // 后续渲染、查询逻辑都直接用cachedTreeData initTreeRender(cachedTreeData); })
- 节点检索直接操作缓存数据:
findNode和getNode函数直接读取已经缓存的cachedTreeData做遍历检索,不需要再触发数据加载流程
function findNode(nodeId) { // 直接遍历缓存的树结构找目标节点,不需要再调用myOntology return cachedTreeData.descendants().find(item => item.data.id === nodeId); }
调整后完全不需要原有的三个自定义嵌套函数,所有数据操作都在同步上下文完成,不会再出现异步卡住的问题。
内容的提问来源于stack exchange,提问作者Victoria Stuart
相关产品推荐
相关产品推荐

