feat(core): add add_nodes API for batch node creation#667
Conversation
…add_nodes method to add multiple nodes efficiently in a single layout pass\n- Update legacy bundle accordingly\n- Add example/test_batch_add.html to demonstrate and benchmark batch addition\n\nRefs: performance optimization for bulk node insertion
| } | ||
|
|
||
| // Phase 2: Unified layout calculation and redraw (execute only once) | ||
| if (created_nodes.some(node => node !== null)) { |
There was a problem hiding this comment.
we can just test !!created_nodes, because null-value won't be added in the list, it's checked at line 495
There was a problem hiding this comment.
在使用库的custom_node_render方法自定义渲染节点的时候,若节点数据的topic为空值时,会直接走进custom_node_render方法渲染自定义的DOM,实际上有些节点在使用场景中,我需要渲染一些span标签用以展示状态,类似于一些UI库的label,为了解决topic为空不走进custom_node_render的问题,我不得不把传入jm.show的数据的空topic转换成 “ ”(中间有个空格),你觉得这个逻辑有必要修复吗
There was a problem hiding this comment.
在使用库的custom_node_render方法自定义渲染节点的时候,若节点数据的topic为空值时,会直接走进custom_node_render方法渲染自定义的DOM,实际上有些节点在使用场景中,我需要渲染一些span标签用以展示状态,类似于一些UI库的label,为了解决topic为空不走进custom_node_render的问题,我不得不把传入jm.show的数据的空topic转换成 “ ”(中间有个空格),你觉得这个逻辑有必要修复吗
你最后提到的“这个逻辑” 是 “topic为空不走进custom_node_render” 吗?如果是的话,我不建议进行修改。如果 node.topic 不存在,说明这个 node 没有实际的语义,你需要展示状态的话,应该给这个 node 设定具体的语义,既然使用了 custom_node_render, 那把一个带有语义的文本写到 node.topic 里我感觉才比较合理。 @UmbraCi 这是我的想法。
There was a problem hiding this comment.
在使用库的custom_node_render方法自定义渲染节点的时候,若节点数据的topic为空值时,会直接走进custom_node_render方法渲染自定义的DOM,实际上有些节点在使用场景中,我需要渲染一些span标签用以展示状态,类似于一些UI库的label,为了解决topic为空不走进custom_node_render的问题,我不得不把传入jm.show的数据的空topic转换成 “ ”(中间有个空格),你觉得这个逻辑有必要修复吗
你最后提到的“这个逻辑” 是 “topic为空不走进custom_node_render” 吗?如果是的话,我不建议进行修改。如果 node.topic 不存在,说明这个 node 没有实际的语义,你需要展示状态的话,应该给这个 node 设定具体的语义,既然使用了 custom_node_render, 那把一个带有语义的文本写到 node.topic 里我感觉才比较合理。 @UmbraCi 这是我的想法。
基础版本的用法是让脑图节点显示文本,进阶玩法应该是让节点能够渲染类似于“富文本”之类的视图,比如一个超链接(可以点击,且显示自定义)、一个状态标签(label组件),这种节点其实是不想渲染出文本的,但是因为custom_node_render方法进入前校验了topic字段是否为空,会导致不渲染自定义节点的问题,为了拓展性,就算不处理,是否加个配置项要好一些呢?我的想法是,既然有custom_node_render这个方法,那是否渲染这个逻辑应该也可以交给它来判断,这个方法也是可以返回boolean值的
There was a problem hiding this comment.
就算不处理,是否加个配置项要好一些呢
既然有custom_node_render这个方法,那是否渲染这个逻辑应该也可以交给它来判断,这个方法也是可以返回boolean值的
技术上可行。我这里考虑的主要是脑图本身数据对象的完整性。如果 node.topic 为空也能代表一定的意义的话,那这部分意义也应该体现在数据对象中。如果这部分意义无法体现在 node.topic 中,我们也可以设计出一个新的字段来代替 topic 去支持 richContent。 但无论如何,我们需要在数据对象中保留它的语义,而不能仅靠 custom_node_render 给节点赋予语义。
There was a problem hiding this comment.
就算不处理,是否加个配置项要好一些呢
既然有custom_node_render这个方法,那是否渲染这个逻辑应该也可以交给它来判断,这个方法也是可以返回boolean值的技术上可行。我这里考虑的主要是脑图本身数据对象的完整性。如果 node.topic 为空也能代表一定的意义的话,那这部分意义也应该体现在数据对象中。如果这部分意义无法体现在 node.topic 中,我们也可以设计出一个新的字段来代替 topic 去支持 richContent。 但无论如何,我们需要在数据对象中保留它的语义,而不能仅靠 custom_node_render 给节点赋予语义。
我的想法是:
给node对象增加一个属性,用以判断是否需要在topic为空的时候也走到richContent中,目前我的做法是遍历整个脑图数据结构,给有需要展示richContent的节点根据data里面的富文本要展示出来的字段来判断
if(node.topic === '' && node.data.label){
// 设置node.topic为一个空格符
}
其实跟你说的这个增加属性的办法殊途同归,只不过我是用空格符强行去满足Boolean(topic),题外话---其实在一些eslint规范中是不推荐直接使用if(Boolean( 字符串 ))判断的;
你看下是否有必要增加这样一个字段来在topic为空的时候让节点继续走到custom_node_render执行渲染呢
There was a problem hiding this comment.
这样的话,我们可以把这段逻辑修改成 node.topic has no value && node.data is empty , 你感觉如何?
There was a problem hiding this comment.
这样的话,我们可以把这段逻辑修改成
node.topic has no value && node.data is empty, 你感觉如何?
是可以达到效果,直接用data对象是否为空来判断,有没有可能会影响到现有其他用户的正常业务逻辑,这一点我有担忧,如果有影响,用户更新库以后,也要修改原本“正常”的业务代码
There was a problem hiding this comment.
是的,这样破坏兼容性了。那我们就加一个 content 字段吧,把它当做 topic 的升级版本。
node.content = {
type: 'plain',
value: 'topic'
}
node.content = {
type: 'html',
value: '<span>...</span>'
}
node.content = {
type: 'some-other-type',
value: any object
}jsmind 支持前两种,其它 type 需要用户自行渲染。
然后判断逻辑改为
if (topic has value or content has value ) {
custom_node_render();
}- Refactor add_node to use private helper methods _add_node_data and _refresh_node_ui - Add add_nodes method for optimized batch node creation - Improve performance by reducing layout calculations from O(n) to O(1) - Add unit tests for add_nodes functionality - Remove add_nodes from legacy version as suggested in PR feedback Addresses feedback from PR hizzgdev#667: - Split add_node into smaller, reusable methods - Simplify condition checking in add_nodes - Focus only on modern ES6 version in src/ directory - Add comprehensive unit tests
- Add 10 test cases covering various scenarios: - Error handling (not editable, parent not found, invalid input) - Core functionality (method calls, parameter passing) - Event handling and return values - Failed node creation scenarios - Use mocking to avoid DOM-related issues in test environment - Ensure proper testing of the batch node creation workflow - All tests pass successfully
- Add performance test for large-scale node creation (1000 nodes) - Add complex data structure test with Unicode and multilingual support - Add comprehensive direction handling test (13 different direction types) - Refactor create_fake_mind to accept options parameter for better flexibility - Remove default editable:true from create_fake_mind, require explicit declaration - Update all test cases to explicitly pass editable:true when needed - Ensure 100% test pass rate with improved test design and clarity Performance improvements verified: - Batch operations call _refresh_node_ui only once (O(1) vs O(n)) - Large node creation completes within 100ms performance threshold - Complex data structures and Unicode characters handled correctly Total test coverage: 13 test cases covering error handling, core functionality, performance optimization, data integrity, and edge cases.
| expect(result).toHaveLength(1000); | ||
| expect(jsmind._add_node_data).toHaveBeenCalledTimes(1000); | ||
| expect(jsmind._refresh_node_ui).toHaveBeenCalledTimes(1); // Key performance benefit | ||
| expect(end - start).toBeLessThan(100); // Should complete within 100ms |
There was a problem hiding this comment.
Cool!
TBH, I don't think we have to check the performance here, because the methods _add_node_data and _refresh_node_ui are mocked. but let's keep it anyway.
There was a problem hiding this comment.
Cool! 凉! TBH, I don't think we have to check the performance here, because the methods
_add_node_dataand_refresh_node_uiare mocked. but let's keep it anyway.TBH,我认为我们不必在这里检查性能,因为_add_node_data和_refresh_node_ui的方法都被嘲笑了。但无论如何,我们还是保留它吧。
不必检查性能的原因是什么呢
There was a problem hiding this comment.
因为这里测不出实际的性能, 真正的 _add_node_data 和 _refresh_node_ui 方法在测试中被 jest.fn 给替代了。
|
@hizzgdev 是否需要先发版一次呢,npm仓库没更新 |
|
感谢提醒 @UmbraCi ,0.9.0 已经发布了 https://www.npmjs.com/package/jsmind |
This PR introduces a new public API add_nodes to efficiently add multiple nodes in one batch.\n\nKey changes:\n- Add add_nodes method in runtime to build nodes without repeated relayout/redraw\n- Update legacy bundle to expose the new API\n- Provide example/test_batch_add.html to benchmark and demonstrate batch addition\n\nWhy:\nAdding nodes one-by-one causes repeated layout and paint. This optimization significantly reduces the cost for bulk insert scenarios.\n\nNotes:\n- API surface follows existing naming and event conventions (fires edit:add_nodes)\n- Backward-compatible; no breaking change\n\nPlease let me know if additional docs or tests are required.