Skip to content

Commit cf34f44

Browse files
committed
feat: Implement Lazy Loading and Deep Array Merging
Introduces 'deepArrays' merge strategy in Neo.mjs and Config.mjs to support array concatenation during config merging. Updates Neo.core.Base to use this strategy for 'remote_', ensuring inherited remote methods (like 'loadFiles') are preserved in subclasses. Implements lazy loading in Neo.main.addon.Base via 'useLazyLoading' config, preventing main thread blocking. Updates Mermaid addon and wrapper to utilize these new capabilities. Closes #8379
1 parent 2f3e047 commit cf34f44

7 files changed

Lines changed: 71 additions & 6 deletions

File tree

src/Neo.mjs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,34 @@ If you intended to create custom logic, use the 'beforeGet${Neo.capitalize(key)}
537537
return target
538538
},
539539

540+
/**
541+
* @param {Object} a
542+
* @param {Object} b
543+
* @returns {Object}
544+
*/
545+
mergeDeepArrays(a, b) {
546+
if (!a) return b;
547+
if (!b) return a;
548+
549+
let out = Neo.clone(a, true);
550+
551+
Object.entries(b).forEach(([key, value]) => {
552+
if (out[key]) {
553+
if (Array.isArray(out[key]) && Array.isArray(value)) {
554+
out[key] = [...new Set([...out[key], ...value])]
555+
} else if (Neo.isObject(out[key]) && Neo.isObject(value)) {
556+
out[key] = Neo.mergeDeepArrays(out[key], value)
557+
} else {
558+
out[key] = value
559+
}
560+
} else {
561+
out[key] = value
562+
}
563+
});
564+
565+
return out
566+
},
567+
540568
/**
541569
* Merges a new value into an existing config value based on a specified strategy.
542570
* This method is used during instance creation to apply merge strategies defined in config descriptors.
@@ -558,6 +586,10 @@ If you intended to create custom logic, use the 'beforeGet${Neo.capitalize(key)}
558586
if (defaultValueType === 'Object' && instanceValueType === 'Object') {
559587
return Neo.merge(Neo.clone(defaultValue, true), instanceValue)
560588
}
589+
} else if (strategy === 'deepArrays') {
590+
if (defaultValueType === 'Object' && instanceValueType === 'Object') {
591+
return Neo.mergeDeepArrays(defaultValue, instanceValue)
592+
}
561593
} else if (typeof strategy === 'function') {
562594
return strategy(defaultValue, instanceValue)
563595
}

src/component/Markdown.mjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ class Markdown extends Component {
127127
}
128128

129129
/**
130-
* @param {String} inputString
131130
* @returns {String}
132131
*/
133132
insertLabDivs(inputString) {

src/component/wrapper/Mermaid.mjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ class Mermaid extends Component {
8585
this.addon = await Neo.currentWorker.getAddon('Mermaid', this.windowId)
8686
}
8787

88+
/**
89+
* @returns {Promise<void>}
90+
*/
91+
async loadFiles() {
92+
return this.addon.loadFiles()
93+
}
94+
8895
/**
8996
* Renders the Mermaid diagram.
9097
* This method waits for the component to be fully initialized (ready) and then invokes

src/core/Base.mjs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,15 @@ class Base {
158158
*
159159
* ONLY supported for singletons.
160160
*
161-
* @member {Object|null} remote_=null
161+
* @member {Object|null} remote_={[isDescriptor]: true, merge: 'deepArrays', value: null}
162162
* @protected
163163
* @reactive
164164
*/
165-
remote_: null
165+
remote_: {
166+
[isDescriptor]: true,
167+
merge : 'deepArrays',
168+
value : null
169+
}
166170
}
167171

168172
/**

src/core/Config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class Config {
5858
/**
5959
* The strategy to use when merging new values into this config.
6060
* Defaults to 'replace'. Can be overridden via a descriptor merge property.
61+
* Supported values: 'deep', 'deepArrays', 'replace', 'shallow'.
6162
* @member {Function|String} mergeStrategy='replace'
6263
*/
6364

src/main/addon/Base.mjs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,21 @@ class Base extends CoreBase {
3030
* @member {Boolean|Number} preloadFilesDelay=5000
3131
* @protected
3232
*/
33-
preloadFilesDelay: 5000
33+
preloadFilesDelay: 5000,
34+
/**
35+
* Remote method access for other workers
36+
* @member {Object} remote
37+
* @protected
38+
*/
39+
remote: {
40+
app: [
41+
'loadFiles'
42+
]
43+
},
44+
/**
45+
* @member {Boolean} useLazyLoading=false
46+
*/
47+
useLazyLoading: false
3448
}
3549

3650
/**
@@ -72,7 +86,11 @@ class Base extends CoreBase {
7286
me.#loadFilesPromiseResolver = resolve
7387
});
7488

75-
if (me.preloadFilesDelay === false) {
89+
if (me.useLazyLoading) {
90+
// Do nothing. The promise remains pending, blocking initAsync (keeping isReady: false).
91+
// Main thread is not blocked because it only waits for remotesReady().
92+
// The first remote call will trigger interception -> cacheMethodCall -> executeLoadFiles.
93+
} else if (me.preloadFilesDelay === false) {
7694
// No automated preload: resolve #loadFilesPromise immediately as it won't be triggered by delay.
7795
// It will only be triggered by cacheMethodCall or initAsync if needed.
7896
me.#loadFilesPromiseResolver();

src/main/addon/Mermaid.mjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ class Mermaid extends Base {
4242
app: [
4343
'render'
4444
]
45-
}
45+
},
46+
/**
47+
* @member {Boolean} useLazyLoading=true
48+
*/
49+
useLazyLoading: true
4650
}
4751

4852
/**

0 commit comments

Comments
 (0)